Various minor improvements in handling incoming requests.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/sqlclient/trunk@20362 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2004-11-19 14:46:42 +00:00
parent 6c0902f3ae
commit 80a269bbde
4 changed files with 180 additions and 56 deletions

View file

@ -1,3 +1,10 @@
Fri Nov 19 14:40:00 2004 Richard Frith-Macdonald <rfm@gnu.org>
* WebServer.m: parse basic authentication infor and set it in extra
headers in request.
* WebServerBundles.m: support handling of paths longer than the
ones set for each bundle.
Tue Nov 11 14:48:05 2004 Nicola Pero <n.pero@mi.flashnet.it>
* GNUmakefile (BUNDLE_INSTALL_DIR): install bundles in

View file

@ -91,6 +91,12 @@
* <desc>The IP address of the host that the request came from.</desc>
* <term>x-remote-port</term>
* <desc>The port of the host that the request came from.</desc>
* <term>x-http-username</term>
* <desc>The username from the 'authorization' header if the request
* supplied http basic authentication.</desc>
* <term>x-http-password</term>
* <desc>The password from the 'authorization' header if the request
* supplied http basic authentication.</desc>
* </deflist>
* On completion, the method must modify response to contain the data
* and headers to be sent out.<br />
@ -387,7 +393,15 @@
* supplied in the request. The WebServerBundles intance is responsible
* for loading the bundles (based on information in the WebServerBundles
* dictionary in the user defaults system) and for forwarding requests
* to the appropriate bundles for processing.
* to the appropriate bundles for processing.<br />
* If a request comes in which is not an exact match for the path of any
* handler, the request path is repeatedly shortened by chopping off the
* last path component until a matching handler is found.<br />
* The paths in the dictionary must <em>not</em> end with a slash...
* an empty string will match all requests which do not match a handler
* with a longer path.
* <example>
* </example>
*/
@interface WebServerBundles : NSObject <WebServerDelegate>
{
@ -408,12 +422,27 @@
* HTTPS server rather than an HTTP server.
* See [WebServer-setPort:secure:] for details.
* </item>
* <item>
* WebServerBundles is a dictionary keyed on path strings, whose
* values are dictionaries, each containing per-handler configuration
* information and the name of the bundle containing the code to handle
* requests sent to the path. NB. the bundle name listed should
* omit the <code>.bundle</code> extension.
* </item>
* </list>
* Returns YES on success, NO on failure (if the port of the WebServer
* cannot be set).
*/
- (BOOL) defaultsUpdate: (NSNotification *)aNotification;
/**
* Returns the handler to be used for the specified path, or nil if there
* is no handler available.<br />
* If the info argument is non-null, it is used to return additional
* information, either the path actually matched, or an error string.
*/
- (id) handlerForPath: (NSString*)path info: (NSString**)info;
/**
* Return dictionary of all handlers by name (path in request which maps
* to that handler instance).
@ -421,7 +450,7 @@
- (NSMutableDictionary*) handlers;
/**
* Return the WebServer instance that the receiver is actiang as a
* Return the WebServer instance that the receiver is acting as a
* delegate for.
*/
- (WebServer*) http;
@ -442,12 +471,22 @@
* information listing the bundle containing the handler to be used.<br />
* The configuration information is a dictionary containing the name
* of the bundle (keyed on 'Name'), and this is used to locate the
* bundle in the applications resources.
* bundle in the applications resources.<br />
* Before a request is passed on to a handler, two extra headers are set
* in it ... <code>x-http-path-base</code> and <code>x-http-path-info</code>
* being the actual path matched for the handler, and the remainder of the
* path after that base part.
*/
- (BOOL) processRequest: (GSMimeDocument*)request
response: (GSMimeDocument*)response
for: (WebServer*)http;
/**
* Registers an object as the handler for a particular path.<br />
* Registering a nil handler destroys any existing handler for the path.
*/
- (void) registerHandler: (id)handler forPath: (NSString*)path;
/**
* Just write to stderr using NSLog.
*/

View file

@ -1235,6 +1235,7 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
GSMimeDocument *request;
GSMimeDocument *response;
BOOL responded = NO;
NSString *str;
NSString *con;
NSMutableData *raw;
NSMutableData *out;
@ -1274,6 +1275,28 @@ unescapeData(const unsigned char* bytes, unsigned length, unsigned char *buf)
value: [[session handle] socketService]
parameters: nil];
str = [[request headerNamed: @"authorization"] value];
if ([str length] > 6 && [[str substringToIndex: 6] caseInsensitiveCompare:
@"Basic "] == NSOrderedSame)
{
str = [[str substringFromIndex: 6] stringByTrimmingSpaces];
str = [GSMimeDocument decodeBase64String: str];
if ([str length] > 0)
{
NSRange r = [str rangeOfString: @":"];
if (r.length > 0)
{
[request setHeader: @"x-http-username"
value: [str substringToIndex: r.location]
parameters: nil];
[request setHeader: @"x-http-password"
value: [str substringFromIndex: NSMaxRange(r)]
parameters: nil];
}
}
}
response = AUTORELEASE([GSMimeDocument new]);
[response setContent: [NSData data] type: @"text/plain" name: nil];

View file

@ -48,6 +48,82 @@
return [_http setPort: port secure: secure];
}
- (id) handlerForPath: (NSString*)path info: (NSString**)info
{
NSString *error = nil;
NSMutableDictionary *handlers;
id handler;
if (info != 0)
{
*info = path;
}
handlers = [self handlers];
handler = [handlers objectForKey: path];
if (handler == nil)
{
NSUserDefaults *defs;
NSDictionary *conf;
NSDictionary *byPath;
defs = [NSUserDefaults standardUserDefaults];
conf = [defs dictionaryForKey: @"WebServerBundles"];
byPath = [conf objectForKey: path];
if ([byPath isKindOfClass: [NSDictionary class]] == NO)
{
NSRange r;
r = [path rangeOfString: @"/" options: NSBackwardsSearch];
if (r.length > 0)
{
path = [path substringToIndex: r.location];
handler = [self handlerForPath: path info: info];
}
else
{
error = [NSString stringWithFormat:
@"Unable to find handler in Bundles config for '%@'", path];
}
}
else
{
NSString *name;
name = [byPath objectForKey: @"Name"];
if ([name length] == 0)
{
error = [NSString stringWithFormat:
@"Unable to find Name in Bundles config for '%@'", path];
}
else
{
NSBundle *mb = [NSBundle mainBundle];
NSString *p = [mb pathForResource: name ofType: @"bundle"];
NSBundle *b = [NSBundle bundleWithPath: p];
Class c = [b principalClass];
if (c == 0)
{
error = [NSString stringWithFormat:
@"Unable to find class in '%@' for '%@'", p, path];
}
else
{
handler = [c new];
[self registerHandler: handler forPath: path];
RELEASE(handler);
}
}
}
}
if (handler == nil && info != 0)
{
*info = error;
}
return handler;
}
- (NSMutableDictionary*) handlers
{
if (_handlers == nil)
@ -109,67 +185,21 @@
response: (GSMimeDocument*)response
for: (WebServer*)http
{
NSString *error;
NSString *path;
NSMutableDictionary *handlers;
NSString *info;
id handler;
path = [[request headerNamed: @"x-http-path"] value];
handlers = [self handlers];
handler = [handlers objectForKey: path];
if (handler == nil)
{
NSUserDefaults *defs;
NSDictionary *conf;
NSDictionary *byPath;
defs = [NSUserDefaults standardUserDefaults];
conf = [defs dictionaryForKey: @"WebServerBundles"];
byPath = [conf objectForKey: path];
if ([byPath isKindOfClass: [NSDictionary class]] == NO)
{
error = [NSString stringWithFormat:
@"Unable to find Bundles config for '%@'", path];
[self webAlert: error for: http];
}
else
{
NSString *name;
name = [byPath objectForKey: @"Name"];
if ([name length] == 0)
{
error = [NSString stringWithFormat:
@"Unable to find Name in Bundles config for '%@'", path];
[self webAlert: error for: http];
}
else
{
NSBundle *mb = [NSBundle mainBundle];
NSString *p = [mb pathForResource: name ofType: @"bundle"];
NSBundle *b = [NSBundle bundleWithPath: p];
Class c = [b principalClass];
if (c == 0)
{
error = [NSString stringWithFormat:
@"Unable to find class in '%@' for '%@'", p, path];
[self webAlert: error for: http];
}
else
{
handler = [c new];
[handlers setObject: handler forKey: path];
RELEASE(handler);
}
}
}
}
handler = [self handlerForPath: path info: &info];
if (handler == nil)
{
NSString *error = @"bad path";
/*
* Log the error message.
*/
[self webAlert: info for: (WebServer*)http];
/*
* Return status code 400 (Bad Request) with the informative error
*/
@ -179,12 +209,37 @@
}
else
{
NSString *extra = [path substringFromIndex: [info length]];
/*
* Provide extra information about the exact path used to match
* the handler, and any remaining path information beyond it.
*/
[request setHeader: @"x-http-path-base"
value: info
parameters: nil];
[request setHeader: @"x-http-path-info"
value: extra
parameters: nil];
return [handler processRequest: request
response: response
for: http];
}
}
- (void) registerHandler: (id)handler forPath: (NSString*)path
{
if (handler == nil)
{
[[self handlers] removeObjectForKey: path];
}
else
{
[[self handlers] setObject: handler forKey: path];
}
}
- (void) webAlert: (NSString*)message for: (WebServer*)http
{
NSLog(@"%@", message);