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