~ubuntu-branches/ubuntu/edgy/sope/edgy

« back to all changes in this revision

Viewing changes to sope-appserver/NGObjWeb/WOHttpAdaptor/WORequestParser.m

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Ley
  • Date: 2005-08-19 16:53:31 UTC
  • Revision ID: james.westby@ubuntu.com-20050819165331-hs683wz1osm708pw
Tags: upstream-4.4rc.2
ImportĀ upstreamĀ versionĀ 4.4rc.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  Copyright (C) 2000-2005 SKYRIX Software AG
 
3
 
 
4
  This file is part of SOPE.
 
5
 
 
6
  SOPE is free software; you can redistribute it and/or modify it under
 
7
  the terms of the GNU Lesser General Public License as published by the
 
8
  Free Software Foundation; either version 2, or (at your option) any
 
9
  later version.
 
10
 
 
11
  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
 
12
  WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
14
  License for more details.
 
15
 
 
16
  You should have received a copy of the GNU Lesser General Public
 
17
  License along with SOPE; see the file COPYING.  If not, write to the
 
18
  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
19
  02111-1307, USA.
 
20
*/
 
21
 
 
22
#include "WORequestParser.h"
 
23
#include <NGStreams/NGBufferedStream.h>
 
24
#include <NGObjWeb/WORequest.h>
 
25
#include "common.h"
 
26
 
 
27
@implementation WORequestParser
 
28
 
 
29
- (id)initWithBufferedStream:(NGBufferedStream *)_in {
 
30
  if (_in == nil) {
 
31
    [self release];
 
32
    return nil;
 
33
  }
 
34
  
 
35
  self->in = [_in retain];
 
36
  self->readByte = (void *)[self->in methodForSelector:@selector(readByte)];
 
37
  return self;
 
38
}
 
39
 
 
40
- (void)dealloc {
 
41
  [self->lastException release];
 
42
  [self->in            release];
 
43
  [super dealloc];
 
44
}
 
45
 
 
46
/* parsing */
 
47
 
 
48
- (void)takeLastException {
 
49
  ASSIGN(self->lastException, [self->in lastException]);
 
50
}
 
51
 
 
52
static inline int nextChar(WORequestParser *self) {
 
53
  int c;
 
54
  if (self->pushBack != 0) {
 
55
    c = self->pushBack;
 
56
    self->pushBack = 0;
 
57
    return c;
 
58
  }
 
59
  if ((c = self->readByte(self->in, @selector(readByte))) < 0)
 
60
    [self takeLastException];
 
61
  return c;
 
62
}
 
63
 
 
64
static inline int nextCharAfterSpaces(WORequestParser *self) {
 
65
  int c;
 
66
  
 
67
  if (self->pushBack != 0) {
 
68
    if (self->pushBack == ' ' || self->pushBack == '\t')
 
69
      self->pushBack = 0;
 
70
    else {
 
71
      c = self->pushBack;
 
72
      self->pushBack = 0;
 
73
      return c;
 
74
    }
 
75
  }
 
76
  
 
77
  do {
 
78
    c = self->readByte(self->in, @selector(readByte));
 
79
    if (c < 0) {
 
80
      [self takeLastException];
 
81
      return c;
 
82
    }
 
83
  }
 
84
  while ((c == ' ') || (c == '\t'));
 
85
  return c;
 
86
}
 
87
static inline BOOL skipSpaces(WORequestParser *self) {
 
88
  int c;
 
89
  
 
90
  if ((c = nextCharAfterSpaces(self)) > 0)
 
91
    return NO;
 
92
  self->pushBack = c;
 
93
  return YES;
 
94
}
 
95
 
 
96
- (BOOL)readCRLF {
 
97
  int c;
 
98
  
 
99
  c = nextChar(self);
 
100
  if (c < 0)     return NO;
 
101
  if (c == '\n') return YES;
 
102
  if (c != '\r') return NO;
 
103
  
 
104
  c = nextChar(self);
 
105
  if (c < 0)     return NO;
 
106
  if (c == '\n') return YES;
 
107
  return NO;
 
108
}
 
109
 
 
110
/* header line */
 
111
 
 
112
- (NSString *)parseMethod {
 
113
  unsigned count;
 
114
  unsigned char m[32];
 
115
  int c;
 
116
  
 
117
  count = 0;
 
118
  for (c = nextChar(self); isalpha(c) && (count < 30); c = nextChar(self)) {
 
119
    m[count] = c;
 
120
    count++;
 
121
  }
 
122
  m[count] = '\0';
 
123
  
 
124
  if (count == 30) {
 
125
    /* method name too long */
 
126
    [self logWithFormat:@"method name got too long"];
 
127
    return nil;
 
128
  }
 
129
  else if (count == 0) {
 
130
    /* method name too short */
 
131
    [self logWithFormat:@"method name got too short"];
 
132
    return nil;
 
133
  }
 
134
  
 
135
  return [NSString stringWithCString:m length:count];
 
136
}
 
137
 
 
138
- (NSString *)parseURI {
 
139
  unsigned char *uri;
 
140
  unsigned      count;
 
141
  NSString      *s;
 
142
  int c;
 
143
  
 
144
  if ((c = nextCharAfterSpaces(self)) < 0)
 
145
    return nil;
 
146
  
 
147
  uri = calloc(4096, sizeof(unsigned char));
 
148
  
 
149
  for (count = 0; count < 4001 && (c > 0); count++) {
 
150
    if (c == ' '  || c == '\t') break;
 
151
    if (c == '\r' || c == '\n') break;
 
152
    
 
153
    uri[count] = c;
 
154
    c = nextChar(self);
 
155
  }
 
156
  
 
157
  if (c < 0) return nil;
 
158
  if (count == 4001) {
 
159
    [self logWithFormat:@"uri got too long (max 4000 chars)"];
 
160
    return nil;
 
161
  }
 
162
  
 
163
  /* feed last char to next parsing step */
 
164
  self->pushBack = c;
 
165
  
 
166
  s = [NSString stringWithCString:uri length:count];
 
167
  if (uri) free(uri);
 
168
  return s;
 
169
}
 
170
 
 
171
- (NSString *)parseVersion {
 
172
  unsigned count;
 
173
  unsigned char m[16];
 
174
  int c;
 
175
  
 
176
  c = nextCharAfterSpaces(self);
 
177
  if (c == '\r' || c == '\n') {
 
178
    /* no version specified */
 
179
    self->pushBack = c;
 
180
    return @"HTTP/0.9";
 
181
  }
 
182
  
 
183
  count = 0;
 
184
  for (; isprint(c) && (count < 15); c = nextChar(self)) {
 
185
    m[count] = c;
 
186
    count++;
 
187
  }
 
188
  m[count] = '\0';
 
189
  
 
190
  if (count == 15) {
 
191
    /* version too long */
 
192
    [self logWithFormat:@"http version got too long"];
 
193
    return nil;
 
194
  }
 
195
  else if (count == 0) {
 
196
    /* version too short, guessing HTTP/0.9 */
 
197
    return @"HTTP/0.9";
 
198
  }
 
199
  
 
200
  return [NSString stringWithCString:m length:count];
 
201
}
 
202
 
 
203
/* headers */
 
204
 
 
205
- (NSDictionary *)parseHeaders {
 
206
  return nil;
 
207
}
 
208
 
 
209
/* body */
 
210
 
 
211
- (unsigned)ramDataSizeLimitation {
 
212
  // 64KB TODO: make default
 
213
  return (64 * 1064);
 
214
}
 
215
- (unsigned)spoolDataSizeLimitation {
 
216
  // 64MB TODO: make default
 
217
  return (64 * 1024 * 1064);
 
218
}
 
219
 
 
220
- (NSData *)readContentUntilEOF {
 
221
  // TODO
 
222
  return nil;
 
223
}
 
224
 
 
225
- (NSData *)readContentOfLength:(unsigned int)_count {
 
226
  if (_count == 0) {
 
227
    static NSData *emptyData = nil;
 
228
    if (emptyData == nil) emptyData = [[NSData alloc] init];
 
229
    return emptyData;
 
230
  }
 
231
  
 
232
  if (_count <= [self ramDataSizeLimitation])
 
233
    return [self->in safeReadDataOfLength:_count];
 
234
  
 
235
  // TODO
 
236
  return nil;
 
237
}
 
238
 
 
239
/* full request */
 
240
 
 
241
- (BOOL)isContentLessMethod:(NSString *)_method {
 
242
  static NSMutableSet *methods = nil;
 
243
  if (methods == nil) {
 
244
    methods = [[NSMutableSet alloc] initWithObjects:nil];
 
245
  }
 
246
  return [methods containsObject:_method];
 
247
}
 
248
 
 
249
- (WORequest *)parseNextRequest {
 
250
  NSString     *method, *uri, *v;
 
251
  NSDictionary *headers;
 
252
  NSData       *content;
 
253
  WORequest    *result;
 
254
 
 
255
  ASSIGN(self->lastException, (id)nil);
 
256
  
 
257
  /* request line */
 
258
  
 
259
  if ((method = [self parseMethod]) == nil)
 
260
    return nil;
 
261
  if ((uri = [self parseURI]) == nil)
 
262
    return nil;
 
263
  if ((v = [self parseVersion]) == nil)
 
264
    return nil;
 
265
  
 
266
  if (![self readCRLF])
 
267
    return nil;
 
268
 
 
269
  [self debugWithFormat:@"stage 1: method=%@ uri=%@ version=%@",
 
270
          method, uri, v];
 
271
  
 
272
  /* headers */
 
273
  
 
274
  if ((headers = [self parseHeaders]) == nil)
 
275
    return nil;
 
276
  
 
277
  /* body */
 
278
  
 
279
  if (![self isContentLessMethod:method]) {
 
280
    unsigned int clen;
 
281
    
 
282
    if ((clen = [[headers objectForKey:@"content-length"] intValue])) {
 
283
      content = [self readContentOfLength:clen];
 
284
    }
 
285
    else {
 
286
      /*
 
287
        Two cases: 
 
288
          HTTP/1.0, HTTP/0.9 - read till EOF if no content-length is set
 
289
          HTTP/1.1 and above: if no content-length is set, body is empty
 
290
      */
 
291
      
 
292
      if ([v hasPrefix:@"HTTP/0"])
 
293
        content = [self readContentUntilEOF];
 
294
      else if ([v hasPrefix:@"HTTP/1.0"])
 
295
        content = [self readContentUntilEOF];
 
296
      else
 
297
        content = nil;
 
298
    }
 
299
  }
 
300
  else
 
301
    content = nil;
 
302
  
 
303
  /* construct */
 
304
  
 
305
  result = [[WORequest alloc] initWithMethod:method uri:uri httpVersion:v
 
306
                              headers:headers content:content
 
307
                              userInfo:nil];
 
308
  return [result autorelease];
 
309
}
 
310
 
 
311
- (NSException *)lastException {
 
312
  return self->lastException;
 
313
}
 
314
 
 
315
/* logging */
 
316
 
 
317
- (NSString *)loggingPrefix {
 
318
  return @"[http-parser]";
 
319
}
 
320
- (BOOL)isDebuggingEnabled {
 
321
  static int debugOn = -1;
 
322
  if (debugOn == -1) {
 
323
    debugOn = [[NSUserDefaults standardUserDefaults]
 
324
                boolForKey:@"WORequestParserDebugEnabled"] ? 1 : 0;
 
325
  }
 
326
  return debugOn ? YES : NO;
 
327
}
 
328
 
 
329
@end /* WORequestParser */