Annotation of libwww/Library/src/HTTPReq.c, revision 2.24
2.1 frystyk 1: /* HTTPReq.c
2.23 frystyk 2: ** HTTP REQUEST GENERATION
2.1 frystyk 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: /* Library Includes */
12: #include "tcp.h"
13: #include "HTUtils.h"
14: #include "HTString.h"
15: #include "HTParse.h"
2.4 frystyk 16: #include "HTFormat.h"
2.11 frystyk 17: #include "HTNetMan.h"
18: #include "HTDNS.h"
2.1 frystyk 19: #include "HTTCP.h"
2.14 frystyk 20: #include "HTAccess.h"
2.17 frystyk 21: #include "HTWWWStr.h"
2.1 frystyk 22: #include "HTWriter.h"
2.10 frystyk 23: #include "HTReqMan.h"
2.1 frystyk 24: #include "HTChunk.h"
2.23 frystyk 25: #include "HTTPGen.h"
2.21 frystyk 26: #include "HTTPUtil.h"
2.1 frystyk 27: #include "HTTPReq.h" /* Implements */
28:
2.24 ! frystyk 29: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
! 30: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
2.1 frystyk 31: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
32:
33: struct _HTStream {
34: CONST HTStreamClass * isa;
35: HTStream * target;
36: HTRequest * request;
2.18 frystyk 37: SOCKET sockfd;
2.11 frystyk 38: int version;
2.1 frystyk 39: BOOL transparent;
40: };
41:
42: /* ------------------------------------------------------------------------- */
43: /* HTTP Output Request Stream */
44: /* ------------------------------------------------------------------------- */
45:
2.11 frystyk 46: /* HTTP09Request
47: ** -------------
48: ** Makes a HTTP/0.9 request
2.1 frystyk 49: */
2.11 frystyk 50: PRIVATE void HTTP09Request (HTStream * me, HTRequest * request)
51: {
52: char *addr = HTAnchor_physical(request->anchor);
53: char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.24 ! frystyk 54: PUTS("GET ");
! 55: PUTS(fullurl);
! 56: PUTC(CR);
! 57: PUTC(LF);
2.11 frystyk 58: }
59:
60: /* HTTPMakeRequest
61: ** ---------------
62: ** Makes a HTTP/1.0-1.1 request header.
63: */
64: PRIVATE void HTTPMakeRequest (HTStream * me, HTRequest * request)
2.1 frystyk 65: {
2.24 ! frystyk 66: char crlf[3];
! 67: char qstr[10];
2.13 frystyk 68: HTParentAnchor *anchor = HTRequest_anchor(request);
2.24 ! frystyk 69: *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0';
2.1 frystyk 70:
71: /* Generate the HTTP/1.0 RequestLine */
72: if (request->method != METHOD_INVALID) {
2.24 ! frystyk 73: PUTS(HTMethod_name(request->method));
! 74: PUTC(' ');
2.1 frystyk 75: } else
2.24 ! frystyk 76: PUTS("GET ");
2.1 frystyk 77:
78: /* If we are using a proxy then only take the `path' info in the URL */
79: {
2.13 frystyk 80: char *addr = HTAnchor_physical(anchor);
2.6 frystyk 81: char *fullurl = HTParse(addr, "", PARSE_PATH|PARSE_PUNCTUATION);
2.1 frystyk 82: if (request->using_proxy) {
2.24 ! frystyk 83: PUTS(fullurl+1);
2.1 frystyk 84: } else {
2.24 ! frystyk 85: PUTS(fullurl);
2.1 frystyk 86: }
87: free(fullurl);
88: }
2.24 ! frystyk 89: PUTS(" HTTP/1.0");
! 90: PUTBLOCK(crlf, 2);
2.1 frystyk 91:
2.4 frystyk 92: /* Request Headers */
2.22 frystyk 93: if (request->RequestMask & HT_C_ACCEPT_TYPE) {
2.1 frystyk 94: int list;
95: HTList *cur;
2.24 ! frystyk 96: BOOL first=YES;
2.1 frystyk 97: for (list=0; list<2; list++) {
2.14 frystyk 98: if ((!list && ((cur = HTFormat_conversion()) != NULL)) ||
99: (list && ((cur = HTRequest_conversion(request)) != NULL))) {
2.4 frystyk 100: HTPresentation *pres;
2.24 ! frystyk 101: while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
2.19 frystyk 102: if (pres->rep_out==WWW_PRESENT && pres->quality <= 1.0) {
2.24 ! frystyk 103: if (first) {
! 104: PUTS("Accept: ");
! 105: first=NO;
! 106: } else
! 107: PUTC(',');
! 108: PUTS(HTAtom_name(pres->rep));
2.1 frystyk 109: if (pres->quality != 1.0) {
2.24 ! frystyk 110: sprintf(qstr, ";q=%1.1f", pres->quality);
! 111: PUTS(qstr);
2.1 frystyk 112: }
113: }
114: }
2.24 ! frystyk 115: if (!first) PUTBLOCK(crlf, 2);
2.1 frystyk 116: }
117: }
118: }
2.22 frystyk 119: if (request->RequestMask & HT_C_ACCEPT_CHAR) {
2.4 frystyk 120: int list;
121: HTList *cur;
2.24 ! frystyk 122: BOOL first=YES;
2.4 frystyk 123: for (list=0; list<2; list++) {
2.14 frystyk 124: if ((!list && ((cur = HTFormat_charset()) != NULL)) ||
125: (list && ((cur = HTRequest_charset(request)) != NULL))) {
2.4 frystyk 126: HTAcceptNode *pres;
127: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 128: if (first) {
2.24 ! frystyk 129: PUTS("Accept-Charset: ");
2.5 frystyk 130: first=NO;
2.24 ! frystyk 131: } else
! 132: PUTC(',');
! 133: PUTS(HTAtom_name(pres->atom));
2.4 frystyk 134: }
2.24 ! frystyk 135: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 136: }
137: }
138: }
2.22 frystyk 139: if (request->RequestMask & HT_C_ACCEPT_ENC) {
2.4 frystyk 140: int list;
141: HTList *cur;
2.24 ! frystyk 142: BOOL first=YES;
2.4 frystyk 143: for (list=0; list<2; list++) {
2.14 frystyk 144: if ((!list && ((cur = HTFormat_encoding()) != NULL)) ||
145: (list && ((cur = HTRequest_encoding(request)) != NULL))) {
2.4 frystyk 146: HTAcceptNode *pres;
147: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 148: if (first) {
2.24 ! frystyk 149: PUTS("Accept-Encoding: ");
2.5 frystyk 150: first=NO;
2.24 ! frystyk 151: } else
! 152: PUTC(',');
! 153: PUTS(HTAtom_name(pres->atom));
! 154: if (pres->quality != 1.0) {
! 155: sprintf(qstr, ";q=%1.1f", pres->quality);
! 156: PUTS(qstr);
2.5 frystyk 157: }
2.4 frystyk 158: }
2.24 ! frystyk 159: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 160: }
161: }
162: }
2.22 frystyk 163: if (request->RequestMask & HT_C_ACCEPT_LAN) {
2.4 frystyk 164: int list;
165: HTList *cur;
2.24 ! frystyk 166: BOOL first=YES;
2.4 frystyk 167: for (list=0; list<2; list++) {
2.14 frystyk 168: if ((!list && ((cur = HTFormat_language()) != NULL)) ||
169: (list && ((cur = HTRequest_language(request)) != NULL))) {
2.4 frystyk 170: HTAcceptNode *pres;
171: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
2.5 frystyk 172: if (first) {
2.24 ! frystyk 173: PUTS("Accept-Language: ");
2.5 frystyk 174: first=NO;
2.24 ! frystyk 175: } else
! 176: PUTC(',');
! 177: PUTS(HTAtom_name(pres->atom));
! 178: if (pres->quality != 1.0) {
! 179: sprintf(qstr, ";q=%1.1f", pres->quality);
! 180: PUTS(qstr);
2.5 frystyk 181: }
2.4 frystyk 182: }
2.24 ! frystyk 183: if (!first) PUTBLOCK(crlf, 2);
2.4 frystyk 184: }
185: }
186: }
187: if (request->authorization != NULL) { /* Put out authorization */
2.24 ! frystyk 188: PUTS("Authorization: ");
! 189: PUTS(request->authorization);
! 190: PUTBLOCK(crlf, 2);
2.1 frystyk 191: }
2.22 frystyk 192: if (request->RequestMask & HT_C_FROM) {
2.1 frystyk 193: CONST char *mailaddress = HTGetMailAddress();
194: if (mailaddress) {
2.24 ! frystyk 195: PUTS("From: ");
! 196: PUTS(mailaddress);
! 197: PUTBLOCK(crlf, 2);
2.1 frystyk 198: }
199: }
2.22 frystyk 200: if (request->RequestMask & HT_C_IMS) {
2.21 frystyk 201: time_t lm = HTAnchor_lastModified(anchor);
2.24 ! frystyk 202: if (lm > 0) {
! 203: PUTS("If-Modified-Since: ");
! 204: PUTS(HTDateTimeStr(&lm, NO));
! 205: PUTBLOCK(crlf, 2);
2.8 frystyk 206: }
207: }
2.22 frystyk 208: if (request->RequestMask & HT_C_HOST) {
2.13 frystyk 209: char *orig = HTAnchor_address((HTAnchor *) anchor);
2.12 frystyk 210: char *host = HTParse(orig, "", PARSE_HOST);
211: char *ptr = strchr(host, ':'); /* Chop off port number */
212: if (ptr) *ptr = '\0';
2.24 ! frystyk 213: PUTS("Host: ");
! 214: PUTS(host);
! 215: PUTBLOCK(crlf, 2);
2.9 frystyk 216: free(orig);
2.12 frystyk 217: free(host);
2.1 frystyk 218: }
2.22 frystyk 219: if (request->RequestMask & HT_C_REFERER && request->parentAnchor) {
2.13 frystyk 220: char *act = HTAnchor_address((HTAnchor *) anchor);
2.1 frystyk 221: char *parent = HTAnchor_address((HTAnchor *) request->parentAnchor);
222: char *relative = HTParse(parent, act,
223: PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
224: if (relative && *relative) {
2.24 ! frystyk 225: PUTS("Referer: ");
! 226: PUTS(parent);
! 227: PUTBLOCK(crlf, 2);
2.1 frystyk 228: }
2.24 ! frystyk 229: FREE(act);
! 230: FREE(parent);
! 231: FREE(relative);
2.1 frystyk 232: }
2.22 frystyk 233: if (request->RequestMask & HT_C_USER_AGENT) {
2.24 ! frystyk 234: PUTS("User-Agent: ");
! 235: PUTS(HTLib_appName());
! 236: PUTC('/');
! 237: PUTS(HTLib_appVersion());
! 238: PUTC(' ');
! 239: PUTS(HTLib_name());
! 240: PUTC('/');
! 241: PUTS(HTLib_version());
! 242: PUTBLOCK(crlf, 2);
2.1 frystyk 243: }
2.23 frystyk 244: if (PROT_TRACE)TTYPrint(TDEST,"HTTP........ Generating Request Headers\n");
2.1 frystyk 245: }
246:
2.16 frystyk 247: PRIVATE int HTTPRequest_put_block (HTStream * me, CONST char * b, int l)
2.1 frystyk 248: {
2.7 frystyk 249: if (!me->target) {
2.1 frystyk 250: return HT_WOULD_BLOCK;
2.7 frystyk 251: } else if (me->transparent)
2.11 frystyk 252: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 253: else {
254: int status;
2.11 frystyk 255: if (me->version == HTTP_09)
256: HTTP09Request(me, me->request);
2.24 ! frystyk 257: else {
2.11 frystyk 258: HTTPMakeRequest(me, me->request); /* Generate header */
2.1 frystyk 259: me->transparent = YES;
2.11 frystyk 260: return b ? PUTBLOCK(b, l) : HT_OK;
2.1 frystyk 261: }
262: return status;
263: }
264: }
265:
2.16 frystyk 266: PRIVATE int HTTPRequest_put_character (HTStream * me, char c)
2.1 frystyk 267: {
2.11 frystyk 268: return HTTPRequest_put_block(me, &c, 1);
2.1 frystyk 269: }
270:
2.16 frystyk 271: PRIVATE int HTTPRequest_put_string (HTStream * me, CONST char * s)
2.1 frystyk 272: {
2.11 frystyk 273: return HTTPRequest_put_block(me, s, strlen(s));
2.1 frystyk 274: }
275:
276: /*
277: ** Flushes data but doesn't free stream object
278: */
2.16 frystyk 279: PRIVATE int HTTPRequest_flush (HTStream * me)
2.1 frystyk 280: {
2.13 frystyk 281: int status = HTTPRequest_put_block(me, NULL, 0);
282: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.1 frystyk 283: }
284:
285: /*
286: ** Flushes data and frees stream object
287: */
2.16 frystyk 288: PRIVATE int HTTPRequest_free (HTStream * me)
2.1 frystyk 289: {
2.11 frystyk 290: int status = HTTPRequest_flush(me);
291: if (status != HT_WOULD_BLOCK) {
292: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
293: return HT_WOULD_BLOCK;
294: free(me);
2.1 frystyk 295: }
2.7 frystyk 296: return status;
2.1 frystyk 297: }
298:
2.16 frystyk 299: PRIVATE int HTTPRequest_abort (HTStream * me, HTList * e)
2.1 frystyk 300: {
2.13 frystyk 301: if (me->target) (*me->target->isa->abort)(me->target, e);
2.1 frystyk 302: free(me);
2.15 frystyk 303: if (PROT_TRACE) TTYPrint(TDEST, "HTTPRequest. ABORTING...\n");
2.1 frystyk 304: return HT_ERROR;
305: }
306:
307: /* HTTPRequest Stream
308: ** -----------------
309: */
310: PRIVATE CONST HTStreamClass HTTPRequestClass =
311: {
312: "HTTPRequest",
313: HTTPRequest_flush,
314: HTTPRequest_free,
315: HTTPRequest_abort,
316: HTTPRequest_put_character,
317: HTTPRequest_put_string,
318: HTTPRequest_put_block
319: };
320:
2.23 frystyk 321: PUBLIC HTStream * HTTPRequest_new (HTRequest * request, HTStream * target,
322: BOOL endHeader)
2.1 frystyk 323: {
324: HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
2.11 frystyk 325: HTdns *dns = HTNet_dns(request->net);
2.1 frystyk 326: if (!me) outofmem(__FILE__, "HTTPRequest_new");
327: me->isa = &HTTPRequestClass;
328: me->target = target;
329: me->request = request;
2.11 frystyk 330: me->version = HTDNS_serverVersion(dns);
2.1 frystyk 331: me->transparent = NO;
2.23 frystyk 332:
333: /* Return general HTTP header stream */
334: return HTTPGen_new(request, me, endHeader);
2.1 frystyk 335: }
Webmaster