Annotation of libwww/Library/src/HTTPReq.c, revision 2.1
2.1 ! frystyk 1: /* HTTPReq.c
! 2: ** MULTITHREADED IMPLEMENTATION OF HTTP CLIENT
! 3: **
! 4: ** This module implements the output stream for HTTP used for sending
! 5: ** requests with or without a entity body.
! 6: **
! 7: ** History:
! 8: ** Jan 95 HFN Written from scratch
! 9: **
! 10: */
! 11:
! 12: /* Library Includes */
! 13: #include "tcp.h"
! 14: #include "HTUtils.h"
! 15: #include "HTString.h"
! 16: #include "HTParse.h"
! 17: #include "HTThread.h"
! 18: #include "HTTCP.h"
! 19: #include "HTWriter.h"
! 20: #include "HTChunk.h"
! 21: #include "HTTPReq.h" /* Implements */
! 22:
! 23: /* Type definitions and global variables etc. local to this module */
! 24: extern char * HTAppName; /* Application name: please supply */
! 25: extern char * HTAppVersion; /* Application version: please supply */
! 26: PUBLIC char * HTProxyHeaders = NULL; /* Headers to pass as-is */
! 27:
! 28: /* Macros and other defines */
! 29: #define HTTP_VERSION "HTTP/1.0"
! 30: #define MIME_VERSION "MIME/1.0"
! 31: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
! 32: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
! 33: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
! 34: #define FREE_TARGET (*me->target->isa->_free)(me->target)
! 35: #define ABORT_TARGET (*me->target->isa->abort)(me->target, e)
! 36:
! 37: /* Type definitions and global variables etc. local to this module */
! 38:
! 39: PRIVATE char linebuf[256]; /* @@@ */
! 40:
! 41: struct _HTStream {
! 42: CONST HTStreamClass * isa;
! 43: HTStream * target;
! 44: char * url;
! 45: HTRequest * request;
! 46: HTChunk * buffer;
! 47: BOOL transparent;
! 48: };
! 49:
! 50: /* ------------------------------------------------------------------------- */
! 51: /* HTTP Output Request Stream */
! 52: /* ------------------------------------------------------------------------- */
! 53:
! 54: /* HTTPMakeRequest
! 55: **
! 56: ** This function composes the HTTP request header.
! 57: */
! 58: PRIVATE void HTTPMakeRequest ARGS2(HTStream *, me, HTRequest *, request)
! 59: {
! 60: HTChunk *header = me->buffer;
! 61: HTParentAnchor *entity =
! 62: (request->CopyRequest && request->CopyRequest->anchor) ?
! 63: request->CopyRequest->anchor : request->anchor;
! 64:
! 65: /* Generate the HTTP/1.0 RequestLine */
! 66: if (request->method != METHOD_INVALID) {
! 67: HTChunkPuts(header, HTMethod_name(request->method));
! 68: HTChunkPutc(header, ' ');
! 69: } else
! 70: HTChunkPuts(header, "GET ");
! 71:
! 72: /* If we are using a proxy then only take the `path' info in the URL */
! 73: {
! 74: char *fullurl = HTParse(me->url, "", PARSE_PATH|PARSE_PUNCTUATION);
! 75: if (request->using_proxy) {
! 76: HTChunkPuts(header, fullurl+1);
! 77: } else {
! 78: HTChunkPuts(header, fullurl);
! 79: }
! 80: free(fullurl);
! 81: }
! 82: HTChunkPutc(header, ' ');
! 83: HTChunkPuts(header, HTTP_VERSION);
! 84: HTChunkPutc(header, CR);
! 85: HTChunkPutc(header, LF);
! 86:
! 87: /* Header Information */
! 88: if (request->HeaderMask & HT_DATE) {
! 89: time_t local = time(NULL);
! 90: sprintf(linebuf, "Date: %s%c%c", HTDateTimeStr(&local, NO), CR,LF);
! 91: HTChunkPuts(header, linebuf);
! 92: }
! 93: if (request->HeaderMask & HT_MESSAGE_ID) {
! 94: CONST char *msgid = HTMessageIdStr();
! 95: if (msgid) {
! 96: sprintf(linebuf, "Message-ID: %s%c%c", msgid, CR, LF);
! 97: HTChunkPuts(header, linebuf);
! 98: }
! 99: }
! 100: if (request->HeaderMask & HT_MIME) {
! 101: sprintf(linebuf, "MIME-Version: %s%c%c", MIME_VERSION, CR, LF);
! 102: HTChunkPuts(header, linebuf);
! 103: }
! 104:
! 105: /* Run through local and global list of conversions for `Accept' lines */
! 106: if (request->HeaderMask & HT_ACCEPT) {
! 107: int list;
! 108: HTList *cur;
! 109: for (list=0; list<2; list++) {
! 110: if ((!list && ((cur=HTConversions) != NULL)) ||
! 111: (list && ((cur=request->conversions) != NULL))) {
! 112: HTPresentation *pres;
! 113: while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
! 114: if (pres->rep_out == WWW_PRESENT) {
! 115: if (pres->quality != 1.0) {
! 116: sprintf(linebuf, "Accept: %s; q=%1.1f%c%c",
! 117: HTAtom_name(pres->rep),
! 118: pres->quality, CR, LF);
! 119: } else {
! 120: sprintf(linebuf, "Accept: %s%c%c",
! 121: HTAtom_name(pres->rep), CR, LF);
! 122: }
! 123: HTChunkPuts(header, linebuf);
! 124: }
! 125: }
! 126: }
! 127: }
! 128: }
! 129:
! 130: /* Put out authorization */
! 131: if (request->authorization != NULL) {
! 132: sprintf(linebuf, "Authorization: %s%c%c", request->authorization,
! 133: CR, LF);
! 134: HTChunkPuts(header, linebuf);
! 135: }
! 136: if (request->HeaderMask & HT_FROM) {
! 137: CONST char *mailaddress = HTGetMailAddress();
! 138: if (mailaddress) {
! 139: sprintf(linebuf, "From: %s%c%c", mailaddress, CR, LF);
! 140: HTChunkPuts(header, linebuf);
! 141: }
! 142: }
! 143: if (request->HeaderMask & HT_PRAGMA) {
! 144: sprintf(linebuf, "Pragma: %s%c%c", "no-cache", CR, LF);
! 145: HTChunkPuts(header, linebuf);
! 146: }
! 147: if (request->HeaderMask & HT_REFERER && request->parentAnchor) {
! 148: char *act = HTAnchor_address((HTAnchor *) request->anchor);
! 149: char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
! 150: char *relative = HTParse(parent, act,
! 151: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
! 152: if (relative && *relative) {
! 153: sprintf(linebuf, "Referer: %s%c%c", parent, CR, LF);
! 154: HTChunkPuts(header, linebuf);
! 155: }
! 156: free(act);
! 157: free(parent);
! 158: free(relative);
! 159: }
! 160: if (request->HeaderMask & HT_USER_AGENT) {
! 161: sprintf(linebuf, "User-Agent: %s/%s libwww/%s%c%c",
! 162: HTAppName ? HTAppName : "unknown",
! 163: HTAppVersion ? HTAppVersion : "0.0",
! 164: HTLibraryVersion, CR, LF);
! 165: HTChunkPuts(header, linebuf);
! 166: }
! 167:
! 168: /* Now put out entity headers if we are using PUT or POST. If we have a
! 169: ** PostAnchor then we take the information from this and uses the
! 170: ** destination anchor to contain the reply. Otherwise, we have created an
! 171: ** anchor (using internal editing etc) and we can use the destination
! 172: ** anchor directly.
! 173: */
! 174: if (request->method==METHOD_PUT || request->method==METHOD_POST) {
! 175: if (request->EntityMask & HT_ALLOW) {
! 176:
! 177: }
! 178: if (request->EntityMask & HT_CONTENT_ENCODING &&
! 179: entity->content_encoding) {
! 180: sprintf(linebuf, "Content-Encoding: %s%c%c",
! 181: HTAtom_name(entity->content_encoding), CR, LF);
! 182: HTChunkPuts(header, linebuf);
! 183: }
! 184: if (request->EntityMask & HT_CONTENT_LANGUAGE) {
! 185:
! 186: }
! 187: if (request->EntityMask & HT_CONTENT_LENGTH) { /* Must be there!!! */
! 188: sprintf(linebuf, "Content-Length: %ld%c%c",
! 189: entity->content_length, CR, LF);
! 190: HTChunkPuts(header, linebuf);
! 191: }
! 192: if (request->EntityMask & HT_CTE && entity->cte) {
! 193: sprintf(linebuf, "Content-Transfer-Encoding: %s%c%c",
! 194: HTAtom_name(entity->cte), CR, LF);
! 195: HTChunkPuts(header, linebuf);
! 196: }
! 197: if (request->EntityMask & HT_CONTENT_TYPE && entity->content_type) {
! 198: sprintf(linebuf, "Content-Type: %s%c%c",
! 199: HTAtom_name(entity->content_type), CR, LF);
! 200: HTChunkPuts(header, linebuf);
! 201: }
! 202: if (request->EntityMask & HT_DERIVED_FROM && entity->derived_from) {
! 203: sprintf(linebuf, "Derived-From: %s%c%c", entity->derived_from,
! 204: CR, LF);
! 205: HTChunkPuts(header, linebuf);
! 206: }
! 207: if (request->EntityMask & HT_EXPIRES) {
! 208:
! 209: }
! 210: if (request->EntityMask & HT_LAST_MODIFIED) {
! 211:
! 212: }
! 213: if (request->EntityMask & HT_LINK) {
! 214:
! 215: }
! 216: if (request->EntityMask & HT_TITLE) {
! 217:
! 218: }
! 219: if (request->EntityMask & HT_URI) {
! 220:
! 221: }
! 222: if (request->EntityMask & HT_VERSION && entity->version) {
! 223: sprintf(linebuf, "Version: %s%c%c", entity->version, CR, LF);
! 224: HTChunkPuts(header, linebuf);
! 225: }
! 226: }
! 227:
! 228: /* Put out extra information if any */
! 229: if (request->ExtraHeaders)
! 230: HTChunkPuts(header, request->ExtraHeaders);
! 231:
! 232: HTChunkPutc(header, CR); /* Blank line means "end" */
! 233: HTChunkPutc(header, LF);
! 234: HTChunkTerminate(header);
! 235: if (PROT_TRACE)
! 236: fprintf(TDEST, "HTTP Tx..... %s", header->data);
! 237: }
! 238:
! 239: PRIVATE int HTTPRequest_put_character ARGS2(HTStream *, me, char, c)
! 240: {
! 241: if (!me->target)
! 242: return HT_WOULD_BLOCK;
! 243: else if (me->transparent)
! 244: return PUTC(c);
! 245: else {
! 246: int status;
! 247: HTTPMakeRequest(me, me->request); /* Generate header */
! 248: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
! 249: me->transparent = YES;
! 250: return PUTC(c);
! 251: }
! 252: return status;
! 253: }
! 254: }
! 255:
! 256: PRIVATE int HTTPRequest_put_string ARGS2(HTStream *, me, CONST char*, s)
! 257: {
! 258: if (!me->target)
! 259: return HT_WOULD_BLOCK;
! 260: else if (me->transparent)
! 261: return PUTS(s);
! 262: else {
! 263: int status;
! 264: HTTPMakeRequest(me, me->request); /* Generate header */
! 265: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
! 266: me->transparent = YES;
! 267: return PUTS(s);
! 268: }
! 269: return status;
! 270: }
! 271: }
! 272:
! 273: PRIVATE int HTTPRequest_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
! 274: {
! 275: if (!me->target)
! 276: return HT_WOULD_BLOCK;
! 277: else if (me->transparent)
! 278: return PUTBLOCK(b, l);
! 279: else {
! 280: int status;
! 281: HTTPMakeRequest(me, me->request); /* Generate header */
! 282: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK) {
! 283: me->transparent = YES;
! 284: return PUTBLOCK(b, l);
! 285: }
! 286: return status;
! 287: }
! 288: }
! 289:
! 290: /*
! 291: ** Flushes data but doesn't free stream object
! 292: */
! 293: PRIVATE int HTTPRequest_flush ARGS1(HTStream *, me)
! 294: {
! 295: if (!me->target)
! 296: return HT_WOULD_BLOCK;
! 297: else if (!me->transparent) {
! 298: int status;
! 299: HTTPMakeRequest(me, me->request); /* Generate header */
! 300: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
! 301: me->transparent = YES;
! 302: else
! 303: return status;
! 304: }
! 305: return HT_OK;
! 306: }
! 307:
! 308: /*
! 309: ** Flushes data and frees stream object
! 310: */
! 311: PRIVATE int HTTPRequest_free ARGS1(HTStream *, me)
! 312: {
! 313: if (!me->target)
! 314: return HT_WOULD_BLOCK;
! 315: else if (!me->transparent) {
! 316: int status;
! 317: HTTPMakeRequest(me, me->request); /* Generate header */
! 318: if ((status=PUTBLOCK(me->buffer->data, me->buffer->size-1)) == HT_OK)
! 319: me->transparent = YES;
! 320: else
! 321: return status;
! 322: }
! 323: if (me->target)
! 324: FREE_TARGET;
! 325: HTChunkFree(me->buffer);
! 326: free(me);
! 327: return HT_OK;
! 328: }
! 329:
! 330: PRIVATE int HTTPRequest_abort ARGS2(HTStream *, me, HTError, e)
! 331: {
! 332: if (me->target)
! 333: ABORT_TARGET;
! 334: FREE(me->url);
! 335: HTChunkFree(me->buffer);
! 336: free(me);
! 337: if (PROT_TRACE)
! 338: fprintf(TDEST, "HTTPRequest. ABORTING...\n");
! 339: return HT_ERROR;
! 340: }
! 341:
! 342: /* HTTPRequest Stream
! 343: ** -----------------
! 344: */
! 345: PRIVATE CONST HTStreamClass HTTPRequestClass =
! 346: {
! 347: "HTTPRequest",
! 348: HTTPRequest_flush,
! 349: HTTPRequest_free,
! 350: HTTPRequest_abort,
! 351: HTTPRequest_put_character,
! 352: HTTPRequest_put_string,
! 353: HTTPRequest_put_block
! 354: };
! 355:
! 356: PUBLIC HTStream * HTTPRequest_new ARGS2(HTRequest *, request,
! 357: HTStream *, target)
! 358: {
! 359: HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
! 360: if (!me) outofmem(__FILE__, "HTTPRequest_new");
! 361: me->isa = &HTTPRequestClass;
! 362: me->target = target;
! 363: me->url = HTAnchor_physical(request->anchor);
! 364: me->request = request;
! 365: me->buffer = HTChunkCreate(512);
! 366: me->transparent = NO;
! 367: return me;
! 368: }
! 369:
! 370:
Webmaster