Annotation of libwww/Library/src/HTTP.c, revision 1.58
1.44 frystyk 1: /* HyperText73 Tranfer Protocol - Client implementation HTTP.c
1.1 timbl 2: ** ==========================
1.2 timbl 3: **
1.55 frystyk 4: ** This module implments the HTTP protocol
5: **
6: ** History:
7: ** < May 24 94 ?? Unknown - but obviosly written
1.56 frystyk 8: ** May 24 94 HF Made reentrent and cleaned up a bit. Implemented
9: ** Forward, redirection, error handling and referer field
1.55 frystyk 10: **
1.1 timbl 11: */
12:
1.2 timbl 13: #define HTTP_VERSION "HTTP/1.0"
1.55 frystyk 14: #define HTTP2 /* Version is greater than 0.9 */
15: #define VERSION_LENGTH 20 /* Number of chars in protocol version */
1.2 timbl 16:
1.55 frystyk 17: /* Uses: */
1.1 timbl 18: #include "HTParse.h"
19: #include "HTUtils.h"
20: #include "tcp.h"
21: #include "HTTCP.h"
22: #include "HTFormat.h"
1.2 timbl 23: #include "HTAlert.h"
24: #include "HTMIME.h"
1.5 timbl 25: #include "HTML.h" /* SCW */
26: #include "HTInit.h" /* SCW */
1.21 luotonen 27: #include "HTAccess.h" /* HTRequest */
1.14 luotonen 28: #include "HTAABrow.h" /* Access Authorization */
1.20 timbl 29: #include "HTTee.h" /* Tee off a cache stream */
30: #include "HTFWriter.h" /* Write to cache file */
1.54 luotonen 31: #include "HTError.h"
1.55 frystyk 32: #include "HTChunk.h"
33: #include "HTTP.h" /* Implements */
34:
35: /* Macros and other defines */
36: #define PUTBLOCK(b, l) (*target->isa->put_block)(target, b, l)
37: #define PUTS(s) (*target->isa->put_string)(target, s)
38: #define FREE_TARGET (*target->isa->free)(target)
1.1 timbl 39:
1.2 timbl 40: struct _HTStream {
41: HTStreamClass * isa; /* all we need to know */
42: };
43:
1.55 frystyk 44: /* Globals */
1.6 timbl 45: extern char * HTAppName; /* Application name: please supply */
46: extern char * HTAppVersion; /* Application version: please supply */
47:
1.50 luotonen 48: #ifdef OLD_CODE
1.37 luotonen 49: PUBLIC long HTProxyBytes = 0; /* Number of bytes transferred thru proxy */
1.50 luotonen 50: #endif
51:
1.37 luotonen 52: extern BOOL using_proxy; /* are we using a proxy gateway? */
53: PUBLIC char * HTProxyHeaders = NULL; /* Headers to pass as-is */
1.23 luotonen 54:
1.55 frystyk 55: /* ------------------------------------------------------------------------- */
56: /* TEMPORARY STUFF - MOVE TO HTML file */
57:
58: typedef struct _http_info {
59: int socket; /* Socket number for communication */
60: HTInputSocket * isoc;
61: } http_info;
62:
63: /* ------------------------------------------------------------------------- */
64:
1.21 luotonen 65: PRIVATE void parse_401_headers ARGS2(HTRequest *, req,
66: HTInputSocket *, isoc)
67: {
68: HTAAScheme scheme;
69: char *line;
70: int num_schemes = 0;
71: HTList *valid_schemes = HTList_new();
72: HTAssocList **scheme_specifics = NULL;
73: char *template = NULL;
74:
75: /* Read server reply header lines */
76:
77: if (TRACE)
78: fprintf(stderr, "Server 401 reply header lines:\n");
79:
80: while (NULL != (line = HTInputSocket_getUnfoldedLine(isoc)) &&
81: *line != 0) {
82:
83: if (TRACE) fprintf(stderr, "%s\n", line);
84:
85: if (strchr(line, ':')) { /* Valid header line */
86:
87: char *p = line;
88: char *fieldname = HTNextField(&p);
89: char *arg1 = HTNextField(&p);
90: char *args = p;
91:
92: if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
93: if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
94: HTList_addObject(valid_schemes, (void*)scheme);
95: if (!scheme_specifics) {
96: int i;
97: scheme_specifics = (HTAssocList**)
98: malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
99: if (!scheme_specifics)
100: outofmem(__FILE__, "parse_401_headers");
101: for (i=0; i < HTAA_MAX_SCHEMES; i++)
102: scheme_specifics[i] = NULL;
103: }
104: scheme_specifics[scheme] = HTAA_parseArgList(args);
105: num_schemes++;
106: }
107: else if (TRACE) {
108: fprintf(stderr, "Unknown scheme `%s' %s\n",
109: (arg1 ? arg1 : "(null)"),
110: "in WWW-Authenticate: field");
111: }
112: }
113:
114: else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
115: if (TRACE)
116: fprintf(stderr, "Protection template set to `%s'\n", arg1);
117: StrAllocCopy(template, arg1);
118: }
119:
120: } /* if a valid header line */
121: else if (TRACE) {
122: fprintf(stderr, "Invalid header line `%s' ignored\n", line);
123: } /* else invalid header line */
1.44 frystyk 124: free(line);
1.21 luotonen 125: } /* while header lines remain */
1.44 frystyk 126: FREE(line);
1.21 luotonen 127: req->valid_schemes = valid_schemes;
128: req->scheme_specifics = scheme_specifics;
129: req->prot_template = template;
130: }
131:
132:
1.55 frystyk 133: /* HTTPCleanup
1.1 timbl 134: **
1.55 frystyk 135: ** This function closes the connection and frees memory.
1.1 timbl 136: **
1.55 frystyk 137: ** Returns 0 on OK, else -1
1.1 timbl 138: */
1.55 frystyk 139: PRIVATE int HTTPCleanup ARGS2(HTRequest *, request, http_info *, http)
1.1 timbl 140: {
1.55 frystyk 141: int status = 0;
142: if (!request) {
143: if (TRACE) fprintf(stderr, "HTTPCleanup. Bad argument!\n");
144: status = -1;
145: } else {
146: if (http->socket >= 0) {
147: if (TRACE) fprintf(stderr, "HTTP........ Closing socket %d\n",
148: http->socket);
149: if ((status = NETCLOSE(http->socket)) < 0)
150: HTErrorSysAdd(request, ERR_FATAL, NO, "NETCLOSE");
151: }
152: }
153: free(http);
154: return status;
155: }
1.36 frystyk 156:
1.23 luotonen 157:
1.55 frystyk 158: /* HTTPSendRequest
159: **
160: ** This function composes and sends a request to the connected server
161: ** specified.
162: **
163: ** Returns 0 on OK, else -1 but does NOT close the connection
1.1 timbl 164: */
1.55 frystyk 165: PRIVATE int HTTPSendRequest ARGS3(HTRequest *, request,
166: http_info *, http, char *, url)
167: {
168: int status = 0;
169: BOOL extensions = YES; /* Assume good HTTP server */
170: HTChunk *command = HTChunkCreate(2048); /* The whole command */
171: if (request->method != METHOD_INVALID) {
172: HTChunkPuts(command, HTMethod_name(request->method));
173: HTChunkPutc(command, ' ');
174: }
175: else
176: HTChunkPuts(command, "GET ");
1.1 timbl 177:
1.55 frystyk 178: /* if we are using a proxy gateway don't copy in the first slash
179: ** of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj
180: ** so that just gohper://.... is sent. */
1.1 timbl 181: {
1.55 frystyk 182: char *p1 = HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION);
183: if (using_proxy)
184: HTChunkPuts(command, p1+1);
1.21 luotonen 185: else
1.55 frystyk 186: HTChunkPuts(command, p1);
187: free(p1);
1.15 luotonen 188: }
1.1 timbl 189:
1.2 timbl 190: #ifdef HTTP2
1.55 frystyk 191: if (extensions) {
192: HTChunkPutc(command, ' ');
193: HTChunkPuts(command, HTTP_VERSION);
194: }
1.2 timbl 195: #endif
1.55 frystyk 196: HTChunkPutc(command, CR); /* CR LF, as in rfc 977 */
197: HTChunkPutc(command, LF);
1.17 timbl 198:
1.55 frystyk 199: if (extensions && HTImProxy && HTProxyHeaders) {
200: HTChunkPuts(command, HTProxyHeaders);
201: } else if (extensions) {
1.56 frystyk 202: char line[256]; /*@@@@ */
1.55 frystyk 203:
204: /* If no conversion list, then put it up, but leave initialization
205: to the client */
206: if (!HTConversions)
207: HTConversions = HTList_new();
1.21 luotonen 208:
1.55 frystyk 209: /* Run through both lists and generate `accept' lines */
210: {
1.17 timbl 211: int i;
1.21 luotonen 212: HTList *conversions[2];
213: conversions[0] = HTConversions;
214: conversions[1] = request->conversions;
1.34 frystyk 215:
1.21 luotonen 216: for (i=0; i<2; i++) {
217: HTList *cur = conversions[i];
218: HTPresentation *pres;
1.55 frystyk 219: while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
220: if (pres->rep_out == WWW_PRESENT) {
1.21 luotonen 221: if (pres->quality != 1.0) {
1.35 frystyk 222: sprintf(line, "Accept: %s; q=%.3f%c%c",
1.21 luotonen 223: HTAtom_name(pres->rep),
224: pres->quality, CR, LF);
225: } else {
226: sprintf(line, "Accept: %s%c%c",
227: HTAtom_name(pres->rep), CR, LF);
228: }
1.55 frystyk 229: HTChunkPuts(command, line);
1.17 timbl 230: }
231: }
1.2 timbl 232: }
1.55 frystyk 233: }
1.22 luotonen 234:
1.56 frystyk 235: /* Put out referer field if any parent */
1.58 ! frystyk 236: if (request->parentAnchor) {
1.56 frystyk 237: char *this = HTAnchor_address((HTAnchor *) request->anchor);
1.58 ! frystyk 238: char *parent = HTAnchor_address((HTAnchor *)request->parentAnchor);
1.56 frystyk 239: char *relative = HTParse(parent, this,
240: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
241: if (relative && *relative) {
242: sprintf(line, "Referer: %s%c%c", parent, CR, LF);
243: HTChunkPuts(command, line);
244: }
245: free(this);
246: free(parent);
247: free(relative);
248: }
1.58 ! frystyk 249:
1.55 frystyk 250: /* Put out user-agent */
1.56 frystyk 251: sprintf(line, "User-Agent: %s/%s libwww/%s%c%c",
252: HTAppName ? HTAppName : "unknown",
253: HTAppVersion ? HTAppVersion : "0.0",
254: HTLibraryVersion, CR, LF);
255: HTChunkPuts(command, line);
1.45 luotonen 256:
1.55 frystyk 257: /* Put out authorization */
258: if (request->authorization != NULL) {
259: HTChunkPuts(command, "Authorization: ");
260: HTChunkPuts(command, request->authorization);
261: HTChunkPutc(command, CR);
262: HTChunkPutc(command, LF);
1.37 luotonen 263: }
1.55 frystyk 264: }
265: HTChunkPutc(command, CR); /* Blank line means "end" */
266: HTChunkPutc(command, LF);
267: HTChunkTerminate(command);
268: if (TRACE) fprintf(stderr, "HTTP Tx..... %s", command->data);
1.17 timbl 269:
1.55 frystyk 270: /* Translate into ASCII if necessary */
1.4 timbl 271: #ifdef NOT_ASCII
1.55 frystyk 272: {
273: char * p;
274: for(p = command; *p; p++) {
275: *p = TOASCII(*p);
1.1 timbl 276: }
1.55 frystyk 277: }
1.3 timbl 278: #endif
1.17 timbl 279:
1.55 frystyk 280: /* Now, we are ready for sending the request */
281: if ((status = NETWRITE(http->socket, command->data, command->size)) < 0) {
282: if (TRACE) fprintf(stderr, "HTTP Tx..... Error sending command\n");
283: HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
284: if (status != HT_INTERRUPTED) {
285: char *unescaped = NULL;
286: StrAllocCopy(unescaped, url);
287: HTUnEscape(unescaped);
288: HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
289: (void *) unescaped, (int) strlen(unescaped),
290: "HTTPSendRequest");
291: free(unescaped);
292: }
293: }
294: HTChunkFree(command);
295: return status;
296: }
297:
298:
299: /* HTTPGetBody
300: **
301: ** Put up a streamstack and read the body from the socket.
302: ** In the special case of user asking for source and the message
303: ** being in MIME, we force the MIME decoding to occur, as it is really
304: ** HTTP decoding. If the user really wants the HTTP headers, he
305: ** can ask for them as www/mime.
306: **
307: ** Returns < 0 on error, else HT_LOADED
308: */
309: PRIVATE int HTTPGetBody ARGS5(HTRequest *, request, http_info *, http,
310: HTInputSocket *, isoc, HTFormat, format_in,
311: BOOL, use_cache)
312: {
313: int status = -1;
314: HTStream *target = NULL; /* Unconverted data */
315: if (format_in == WWW_MIME && request->output_format == WWW_SOURCE) {
316: target = HTMIMEConvert(request, NULL, format_in,
317: request->output_format,
318: request->output_stream);
319: } else
320: target = HTStreamStack(format_in, request, NO);
321: if (target) {
322:
323: /* @@ Bug: The decision of whether or not to cache should also
324: be made contingent on a IP address match or non match. */
325:
326: if (HTCacheDir && use_cache) {
327: target = HTTee(target,
328: HTCacheWriter(request, NULL, format_in,
329: request->output_format,
330: request->output_stream));
1.17 timbl 331: }
1.55 frystyk 332:
333: /* Push the data down the stream remembering the end of the
334: first buffer we just read */
335: if (format_in == WWW_HTML)
336: target = HTNetToText(target);/* Pipe through CR stripper */
337:
338: PUTBLOCK(isoc->input_pointer,
339: isoc->input_limit-isoc->input_pointer);
340: HTCopy(http->socket, target); /* USE RETURN AS STATUS */
341: FREE_TARGET;
342: status = HT_LOADED;
343: }
344: return status;
345: }
346:
347:
1.56 frystyk 348: /* HTTPRedirect
349: **
350: ** Reads the response from a 3xx server status code. Only the first line
351: ** is read. The format expected is
352: **
353: ** Location: <url> String CrLf
354: **
355: ** The comment string is ignored!
356: **
357: ** NOTE: THIS IS NOT IN CORRESPONDANCE WITH THE SPECS!!!
358: **
359: ** Returns new anchor on success else NULL
360: */
361: PRIVATE HTAnchor *HTTPRedirect ARGS3(HTRequest *, request,
362: HTInputSocket *, isoc, int, code)
363: {
364: BOOL found = NO;
365: HTAnchor *anchor = NULL; /* New anchor */
366: char *line;
367: if (TRACE)
368: fprintf(stderr, "Redirection. Looking for URL's\n");
369: while ((line = HTInputSocket_getUnfoldedLine(isoc)) != NULL) {
370: char *strptr = line;
371: if (*strptr) {
372: while (*strptr && *strptr == ' ') /* Skip leading spaces */
373: strptr++;
374: if (!strncasecomp(strptr, "location:", 9)) {
375: char *url = strchr(strptr, ' ');
376: char *comment;
377: while (*url && *url == ' ') /* Skip leading spaces */
378: url++;
379: if ((comment = strchr(url, ' ')) != NULL)
380: *comment = '\0'; /* Skip any comments */
381: if (code == 301)
1.57 frystyk 382: HTErrorAdd(request, ERR_INFO, NO, HTERR_MOVED,
1.56 frystyk 383: (void *) url, (int) strlen(url),
384: "HTTPRedirect");
385: else if (code == 302)
1.57 frystyk 386: HTErrorAdd(request, ERR_INFO, NO, HTERR_FOUND,
1.56 frystyk 387: (void *) url, (int) strlen(url),
388: "HTTPRedirect");
389: else {
390: if (TRACE)
391: fprintf(stderr,
392: "Redirection. Weird, should never happen\n");
393: }
394:
395: /* Now use the new anchor instead of the old one */
396: anchor = HTAnchor_findAddress(url);
397: found = YES;
398: FREE(line);
399: break;
400: }
401: }
402: free(line);
403: }
404:
405: if (!found) {
406: int length = (int) strlen(line);
407: HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
408: (void *) line, length < 50 ? length : 50, "HTTPRedirect");
409: }
410: return anchor;
411: }
412:
413:
1.55 frystyk 414: /* Load Document from HTTP Server HTLoadHTTP()
415: ** ==============================
416: **
417: ** Given a hypertext address, this routine loads a document.
418: **
419: ** On entry,
420: ** request This is the request structure
421: ** On exit,
422: ** returns <0 Error has occured
1.58 ! frystyk 423: ** HT_LOADED if return status 200 OK
! 424: ** HT_NO_DATA if return status 204 No Response
1.55 frystyk 425: */
426: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
427: {
428: char *url;
429: int status = -1; /* tcp return */
430: http_info *http; /* Specific protocol information */
431:
432: if (!request || !request->anchor) {
433: if (TRACE) fprintf(stderr, "HTLoadHTTP.. Bad argument\n");
434: return -1;
435: }
436: url = HTAnchor_physical(request->anchor);
437: HTSimplify(url);
438: if (TRACE) fprintf(stderr, "HTTP........ Looking for `%s\'\n", url);
439:
440: /* Initiate a new http structure */
441: if ((http = (http_info *) calloc(1, sizeof(http_info))) == NULL)
442: outofmem(__FILE__, "HTLoadHTTP");
443: http->socket = -1;
1.17 timbl 444:
1.55 frystyk 445: /*
446: ** Compose authorization information (this was moved here
447: ** from after the making of the connection so that the connection
448: ** wouldn't have to wait while prompting username and password
449: ** from the user). -- AL 13.10.93
450: */
451: HTAA_composeAuth(request);
452: if (TRACE) {
453: if (request->authorization)
454: fprintf(stderr, "HTTP........ Sending Authorization: %s\n",
455: request->authorization);
456: else
457: fprintf(stderr, "HTTP........ Not sending authorization (yet)\n");
458: }
459:
460: /* Now let's set up a connection */
461: if ((status = HTDoConnect(request, url, TCP_PORT,
462: &http->socket, NULL)) < 0) {
463: if (TRACE)
464: fprintf(stderr, "HTTP........ Connection not established!\n");
465: if (status != HT_INTERRUPTED) {
466: char *unescaped = NULL;
467: StrAllocCopy(unescaped, url);
468: HTUnEscape(unescaped);
469: HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
470: (void *) unescaped, (int) strlen(unescaped),
471: "HTLoadHTTP");
472: free(unescaped);
473: }
474: HTTPCleanup(request, http);
475: return status;
476: }
477: if (TRACE) fprintf(stderr, "HTTP........ Connected, socket %d\n",
478: http->socket);
479:
480: /* Compose the request and send it over the net */
481: if ((status = HTTPSendRequest(request, http, url)) < 0) {
482: HTTPCleanup(request, http);
483: return status;
484: }
1.2 timbl 485:
1.17 timbl 486: /* Read the response
487: ** -----------------
1.11 timbl 488: **
489: ** HTTP0 servers must return ASCII style text, though it can in
490: ** principle be just text without any markup at all.
491: ** Full HTTP servers must return a response
492: ** line and RFC822 style header. The response must therefore in
493: ** either case have a CRLF somewhere soon.
494: **
495: ** This is the theory. In practice, there are (1993) unfortunately
496: ** many binary documents just served up with HTTP0.9. This
497: ** means we have to preserve the binary buffer (on the assumption that
498: ** conversion from ASCII may lose information) in case it turns
499: ** out that we want the binary original.
1.2 timbl 500: */
1.53 luotonen 501:
502: CTRACE(stderr, "Waiting..... for response\n");
503:
1.37 luotonen 504: if (HTImProxy) {
1.24 luotonen 505:
1.22 luotonen 506: /*
507: ** Server as a gateway -- send body of the message
508: ** received from client (if any).
509: */
510: if (request->isoc && request->content_length > 0) {
511: int remain = request->content_length;
512: int i = remain;
513: char * buf;
514:
515: while (remain > 0 &&
516: (buf = HTInputSocket_getBlock(request->isoc, &i))) {
1.55 frystyk 517: int status = NETWRITE(http->socket, buf, i);
1.22 luotonen 518: if (status < 0) {
1.27 luotonen 519: CTRACE(stderr, "HTTPAccess.. Unable to forward body\n");
1.55 frystyk 520: HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
521: HTTPCleanup(request, http);
522: return status;
1.22 luotonen 523: }
524: remain -= i;
525: i = remain;
526: }
527: }
1.23 luotonen 528:
529: /*
1.22 luotonen 530: ** Load results directly to client
531: */
1.55 frystyk 532: HTCopy(http->socket, request->output_stream);
1.25 luotonen 533: (*request->output_stream->isa->free)(request->output_stream);
1.55 frystyk 534: HTTPCleanup(request, http);
1.22 luotonen 535: return HT_LOADED;
1.55 frystyk 536: } else { /* read response */
1.21 luotonen 537:
1.17 timbl 538: HTFormat format_in; /* Format arriving in the message */
1.55 frystyk 539: HTInputSocket *isoc = HTInputSocket_new(http->socket);
540: char *status_line = HTInputSocket_getStatusLine(isoc);
1.2 timbl 541:
1.11 timbl 542: /* Kludge to trap binary responses from illegal HTTP0.9 servers.
543: ** First time we have enough, look at the stub in ASCII
544: ** and get out of here if it doesn't look right.
545: **
546: ** We also check for characters above 128 in the first few bytes, and
547: ** if we find them we forget the html default.
548: **
549: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
550: ** will be taken as a HTTP 1.0 server. Failure.
551: ** An HTTP 0.9 server returning a binary document with
552: ** characters < 128 will be read as ASCII.
553: */
1.36 frystyk 554: /* If HTTP 0 response, then DO NOT CACHE (Henrik 14/02-94) */
555: if (!status_line) {
1.21 luotonen 556: if (HTInputSocket_seemsBinary(isoc)) {
557: format_in = HTAtom_for("www/unknown");
1.55 frystyk 558: } else {
1.21 luotonen 559: format_in = WWW_HTML;
560: }
1.55 frystyk 561: status = HTTPGetBody(request, http, isoc, format_in, NO);
562: } else {
1.21 luotonen 563: /*
564: ** We now have a terminated server status line, and we have
565: ** checked that it is most probably a legal one. Parse it.
566: */
567: char server_version[VERSION_LENGTH+1];
568: int server_status;
569:
570: if (TRACE)
1.55 frystyk 571: fprintf(stderr, "HTTP Rx..... `%.70s\'\n", status_line);
572: {
573: char formatstr[20];
574: sprintf(formatstr, "%%%ds%%d", VERSION_LENGTH);
575: if (sscanf(status_line, formatstr, server_version,
576: &server_status) < 2) {
577: int length = (int) strlen(status_line);
578: HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
579: (void *) status_line, length < 50 ? length : 50,
580: "HTLoadHTTP");
581: HTInputSocket_free(isoc);
582: free(http);
583: free(status_line);
584: return -1; /* Bad response */
585: }
586: *(server_version+VERSION_LENGTH) = '\0';
587: }
1.21 luotonen 588: format_in = HTAtom_for("www/mime");
1.7 timbl 589:
1.55 frystyk 590: /* Big switch for all response codes */
591: switch (server_status/100) {
1.2 timbl 592:
1.55 frystyk 593: case 2: /* Good: Got MIME object */
1.58 ! frystyk 594: switch (server_status) {
! 595: case 204: /* No response */
! 596: HTErrorAdd(request, ERR_INFO, NO, HTERR_NO_RESPONSE,
! 597: NULL, 0, "HTLoadHTTP");
! 598: status = HT_NO_DATA;
! 599: break; /* Don't get any body */
! 600: case 203: /* Partial */
! 601: HTErrorAdd(request, ERR_INFO, NO, HTERR_PARTIAL,
! 602: NULL, 0, "HTLoadHTTP");
! 603: /* Drop through to 200 as we still have to get the body */
! 604: case 200:
! 605: status = HTTPGetBody(request, http, isoc, format_in, YES);
! 606: break;
! 607: default:
! 608: {
! 609: int length = (int) strlen(status_line);
! 610: HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
! 611: (void *) status_line, length < 50 ?
! 612: length : 50, "HTLoadHTTP");
! 613: }
! 614: status = -1;
! 615: break;
! 616: }
1.21 luotonen 617: break;
1.58 ! frystyk 618:
1.21 luotonen 619: case 3: /* Various forms of redirection */
1.55 frystyk 620: switch (server_status) {
621: case 301: /* Moved */
622: case 302: /* Found */
1.56 frystyk 623: {
624: HTParentAnchor *anchor;
625: if ((anchor = (HTParentAnchor *)
626: HTTPRedirect(request, isoc,
627: server_status)) != NULL) {
628: free(status_line);
629: HTInputSocket_free(isoc);
630: HTTPCleanup(request, http);
1.58 ! frystyk 631:
! 632: /* Now do a recursive call but keep error stack */
! 633: if (HTLoadAnchorRecursive((HTAnchor *) anchor,
! 634: request) == YES)
1.56 frystyk 635: return HT_LOADED;
636: else
637: return -1;
638: }
639: }
640: break;
1.55 frystyk 641: case 303: /* Method */
1.56 frystyk 642: HTAlert("This client doesn't support automatic redirection of type `Method'");
643: status = -1;
1.55 frystyk 644: break;
645: case 304: /* Not modified Since */
646: {
647: char *unescaped = NULL;
648: StrAllocCopy(unescaped, url);
649: HTUnEscape(unescaped);
1.57 frystyk 650: HTErrorAdd(request, ERR_INFO, NO,
1.55 frystyk 651: HTERR_NOT_MODIFIED, (void *) unescaped,
652: (int) strlen(unescaped), "HTLoadHTTP");
653: free(unescaped);
654: }
655: status = HT_LOADED;
656: break;
657:
658: default:
659: {
660: int length = (int) strlen(status_line);
661: HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
662: (void *) status_line, length < 50 ?
663: length : 50, "HTLoadHTTP");
664: }
665: status = -1;
666: break;
667: }
1.21 luotonen 668: break;
1.17 timbl 669:
1.21 luotonen 670: case 4: /* Access Authorization problem */
671: switch (server_status) {
672: case 401:
673: parse_401_headers(request, isoc);
674:
675: if (TRACE) fprintf(stderr, "%s %d %s\n",
1.55 frystyk 676: "HTTP: close socket", http->socket,
1.21 luotonen 677: "to retry with Access Authorization");
1.24 luotonen 678: if (HTAA_retryWithAuth(request, HTLoadHTTP)) {
1.21 luotonen 679: status = HT_LOADED;/* @@ THIS ONLY WORKS ON LINEMODE */
1.55 frystyk 680: break;
1.21 luotonen 681: }
682: /* else falltrough */
683: default:
1.14 luotonen 684: {
1.55 frystyk 685: char *unescaped = NULL;
686: StrAllocCopy(unescaped, url);
687: HTUnEscape(unescaped);
688: HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
689: (void *) unescaped,
690: (int) strlen(unescaped), "HTLoadHTTP");
691: free(unescaped);
692: #ifdef OLD_CODE
693: char *p1 = HTParse(url, "", PARSE_HOST);
1.21 luotonen 694: char * message;
695:
696: if (!(message = (char*)malloc(strlen(status_line) +
697: strlen(p1) + 100)))
698: outofmem(__FILE__, "HTTP 4xx status");
1.14 luotonen 699: sprintf(message,
1.21 luotonen 700: "HTTP server at %s replies:\n%s\n\n%s\n",
701: p1, status_line,
702: ((server_status == 401)
703: ? "Access Authorization package giving up.\n"
704: : ""));
1.22 luotonen 705: status = HTLoadError(request, server_status, message);
1.14 luotonen 706: free(message);
707: free(p1);
1.55 frystyk 708: #endif /* OLD_CODE */
1.14 luotonen 709: }
1.55 frystyk 710: status = -1;
711: break;
712: }
1.21 luotonen 713: break;
714:
715: case 5: /* I think you goofed */
716: {
1.55 frystyk 717: char *unescaped = NULL;
718: StrAllocCopy(unescaped, url);
719: HTUnEscape(unescaped);
720: HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
721: (void *) unescaped, (int) strlen(unescaped),
722: "HTLoadHTTP");
723: free(unescaped);
724: #ifdef OLD_CODE
725: char *p1 = HTParse(url, "", PARSE_HOST);
1.21 luotonen 726: char * message = (char*)malloc(strlen(status_line) +
727: strlen(p1) + 100);
728: if (!message) outofmem(__FILE__, "HTTP 5xx status");
729: sprintf(message,
730: "HTTP server at %s replies:\n%s", p1, status_line);
1.22 luotonen 731: status = HTLoadError(request, server_status, message);
1.21 luotonen 732: free(message);
733: free(p1);
1.55 frystyk 734: #endif
1.21 luotonen 735: }
1.55 frystyk 736: status = -1;
1.21 luotonen 737: break;
1.55 frystyk 738:
739: default: /* bad number */
740: {
741: int length = (int) strlen(status_line);
742: HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
743: (void *) status_line, length < 50 ? length : 50,
744: "HTLoadHTTP");
745: }
746: status = -1;
1.21 luotonen 747: break;
1.55 frystyk 748: }
749: FREE(status_line); /* Leak fix Henrik 18/02-94 */
1.17 timbl 750: }
1.48 timbl 751:
1.55 frystyk 752: /* Close the socket and free memory */
753: HTInputSocket_free(isoc);
754: HTTPCleanup(request, http);
755: return status; /* Good return */
756: }
757: }
1.1 timbl 758:
759: /* Protocol descriptor
760: */
761:
1.17 timbl 762: GLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0, 0 };
1.55 frystyk 763:
764:
1.21 luotonen 765:
Webmaster