/* Converter from \n to CRLF ** ------------------------- ** The input is assumed to be in local representation with lines ** delimited by \n. The \n when found is changed to a CRLF sequence, ** the network representation of a new line. ** Conversion: '\r' is stripped and \n => CRLF */ PRIVATE int TextToNet_put_block (HTStream * me, const char* b, int len) { int status; #if 0 const char *limit = b+len; #endif if (!me->start) me->start = b; else { len -= (me->start - b); b = me->start; } while (len-- > 0) { if (me->had_cr && *b == LF) { if (b > me->start+1) { if ((status = PUTBLOCK(me->start, b - me->start-1)) != HT_OK) return status; } me->start = b+1; if ((status = PUTC('\n')) != HT_OK) return status; } me->had_cr = (*b++ == CR); } if (me->start < b && (status = PUTBLOCK(me->start, b-me->start)) != HT_OK) return status; me->start = NULL; /* Whole buffer is written :-) */ return HT_OK; }
/* Converter from CRLF to \n ** ------------------------- ** The input is assumed to be in local representation with lines ** delimited by (CR,LF) pairs in the local representation. ** The conversion to local representation is always done in HTSocket.c ** The (CR,LF) sequence when found is changed to a '\n' character, ** the internal C representation of a new line. */ PRIVATE int NetToText_put_block (HTStream * me, const char * s, int l) { int status; if (!me->start) me->start = s; else { l -= (me->start - s); s = me->start; } while (l-- > 0) { if (me->had_cr && *s == LF) { if (s > me->start+1) { if ((status = PUTBLOCK(me->start, s - me->start-1)) != HT_OK) return status; } me->start = s+1; if ((status = PUTC('\n')) != HT_OK) return status; } me->had_cr = (*s++ == CR); } if (me->start < s && (status = PUTBLOCK(me->start, s-me->start)) != HT_OK) return status; me->start = NULL; /* Whole buffer is written :-) */ return HT_OK; }
/* ** Searches for NNTP header line until buffer fills up or a CRLF or LF ** is found */ PRIVATE int HTNewsStatus_put_block (HTStream * me, const char * b, int l) { int status; HTHost_setConsumed(me->host, l); while (!me->semi_trans && l-- > 0) { if (me->EOLstate == EOL_FCR) { if (*b == LF) { if (me->junk) me->junk = NO; me->EOLstate = EOL_BEGIN; if ((status = ScanResponse(me)) != HT_LOADED) return status; } } else if (*b == CR) { me->EOLstate = EOL_FCR; } else if (*b == LF) { if (me->junk) me->junk = NO; me->EOLstate = EOL_BEGIN; if ((status = ScanResponse(me)) != HT_LOADED) return status; } else { *(me->buffer+me->buflen++) = *b; if (me->buflen >= MAX_NEWS_LINE) { HTTRACE(PROT_TRACE, "News Status. Line too long - chopped\n"); me->junk = YES; if ((status = ScanResponse(me)) != HT_LOADED) return status; } } b++; } /* ** Now see if we have parts of the body to put down the stream pipe. ** At this point we are looking for CRLF.CRLF. We are guaranteed a stream */ if (l > 0) { int rest = l; const char *ptr = b; while (rest-- > 0) { if (*ptr == CR) { me->EOLstate = me->EOLstate==EOL_DOT ? EOL_SCR : EOL_FCR; } else if (*ptr == '.') { me->EOLstate = me->EOLstate==EOL_FLF ? EOL_DOT : EOL_BEGIN; } else if (*ptr == LF) { me->EOLstate = me->EOLstate>EOL_DOT ? EOL_SLF : EOL_FLF; } else me->EOLstate = EOL_BEGIN; ptr++; } if (me->EOLstate == EOL_SLF) { int status = PUTBLOCK(b, l-5); return status != HT_OK ? status : HT_LOADED; } else { int status = PUTBLOCK(b, l); return status; } } return HT_LOADED; }
PRIVATE int HTTPReply_put_block (HTStream * me, const char * b, int l) { if (me->transparent) return b ? PUTBLOCK(b, l) : HT_OK; else { MakeReplyPipe(me, me->request); me->transparent = YES; return b ? PUTBLOCK(b, l) : HT_OK; } }
PRIVATE int HTTPResponse_put_block (HTStream * me, const char * b, int l) { if (me->target) { if (me->transparent) return PUTBLOCK(b, l); else { HTTPMakeResponse(me, me->request); /* Generate header */ me->transparent = YES; return b ? PUTBLOCK(b, l) : HT_OK; } } return HT_WOULD_BLOCK; }
NAMESPACE_END void RC6Encryption::ProcessBlock(const byte *in, byte *out) const { const RC6_WORD *sptr = sTable; RC6_WORD a, b, c, d, t, u; GETBLOCK(in, a, b, c, d); b += sptr[0]; d += sptr[1]; sptr += 2; for(unsigned i=0; i<r; i++) { t = ROTL(b*(2*b+1), 5); u = ROTL(d*(2*d+1), 5); a = ROTL(a^t,u) + sptr[0]; c = ROTL(c^u,t) + sptr[1]; t = a; a = b; b = c; c = d; d = t; sptr += 2; } a += sptr[0]; c += sptr[1]; PUTBLOCK(out, a, b, c, d); }
void RC6Decryption::ProcessBlock(const byte *in, byte *out) const { const RC6_WORD *sptr = sTable+sTable.size; RC6_WORD a, b, c, d, t, u; GETBLOCK(in, a, b, c, d); sptr -= 2; c -= sptr[1]; a -= sptr[0]; for (unsigned i=0; i < r; i++) { sptr -= 2; t = a; a = d; d = c; c = b; b = t; u = ROTL(d*(2*d+1), 5); t = ROTL(b*(2*b+1), 5); c = ROTR(c-sptr[1], t) ^ u; a = ROTR(a-sptr[0], u) ^ t; } sptr -= 2; d -= sTable[1]; b -= sTable[0]; PUTBLOCK(out, a, b, c, d); }
/* HTTPMakeResponse ** ---------------- ** Makes a HTTP/1.0-1.1 response header. */ PRIVATE int HTTPMakeResponse (HTStream * me, HTRequest * request) { char crlf[3]; HTRsHd response_mask = HTRequest_rsHd(request); *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0'; if (response_mask & HT_S_LOCATION) { /* @@@ */ } if (response_mask & HT_S_PROXY_AUTH) { /* @@@ */ } if (response_mask & HT_S_PUBLIC) { /* @@@ */ } if (response_mask & HT_S_RETRY_AFTER) { /* @@@ */ } if (response_mask & HT_S_SERVER) { PUTS("Server: "); PUTS(HTLib_appName()); PUTC('/'); PUTS(HTLib_appVersion()); PUTC(' '); PUTS(HTLib_name()); PUTC('/'); PUTS(HTLib_version()); PUTBLOCK(crlf, 2); } if (response_mask & HT_S_WWW_AUTH) { /* @@@ */ } HTTRACE(PROT_TRACE, "HTTP........ Generating Response Headers\n"); return HT_OK; }
PRIVATE int NewsPost_put_block (HTStream * me, const char* b, int l) { if (!me->target) { return HT_WOULD_BLOCK; } else if (me->transparent) return b ? PUTBLOCK(b, l) : HT_OK; else { int status; NewsPost_start(me, me->request); if ((status = PUTBLOCK(HTChunk_data(me->buffer), HTChunk_size(me->buffer))) == HT_OK) { me->transparent = YES; return b ? PUTBLOCK(b, l) : HT_OK; } return status; } }
PRIVATE int HTBufferWriter_write (HTOutputStream * me, const char * buf, int len) { int status; while (1) { int available = me->data + me->allocated - me->read; /* If we have enough buffer space */ if (len <= available) { int size = 0; memcpy(me->read, buf, len); me->read += len; /* If we have accumulated enough data then flush */ if ((size = me->read - me->data) > me->growby) { me->lastFlushTime = HTGetTimeInMillis(); status = PUTBLOCK(me->data, size); if (status == HT_OK) { me->read = me->data; } else { return (status == HT_WOULD_BLOCK) ? HT_OK : HT_ERROR; } } return HT_OK; } else { /* Fill the existing buffer (if not already) and flush */ if (available) { memcpy(me->read, buf, available); buf += available; len -= available; me->read += available; } me->lastFlushTime = HTGetTimeInMillis(); status = PUTBLOCK(me->data, me->allocated); if (status == HT_OK) { me->read = me->data; } else if (status == HT_WOULD_BLOCK) { HTBufferWriter_addBuffer(me, len); memcpy(me->read, buf, len); me->read += len; return HT_OK; } } } }
/* NewsPost_end ** ------------ ** End the posting by CRLF.CRLF ** returns whatever PUT_BLOCK returns */ PRIVATE int NewsPost_end (HTStream * me) { char buf[6]; *buf = CR; *(buf+1) = LF; *(buf+2) = '.'; *(buf+3) = CR; *(buf+4) = LF; *(buf+5) = '\0'; return PUTBLOCK(buf, 5); }
PRIVATE int HTTPRequest_put_block (HTStream * me, const char * b, int l) { if (!me->target) { return HT_WOULD_BLOCK; } else if (me->transparent) return b ? PUTBLOCK(b, l) : HT_OK; else { int status = HT_OK; if (me->version == HTTP_09) { status = HTTP09Request(me, me->request); if (status != HT_OK) return status; } else { status = HTTPMakeRequest(me, me->request); if (status != HT_OK) return status; me->transparent = YES; return b ? PUTBLOCK(b, l) : HT_OK; } return status; } }
/* ** This function is only called from either FlushEvent or HTBufferWriter_lazyFlush ** which means that only the host object or timeout can cause a flush */ PRIVATE int HTBufferWriter_flush (HTOutputStream * me) { int status = HT_OK; if (me && me->read > me->data) { me->lastFlushTime = HTGetTimeInMillis(); if ((status = PUTBLOCK(me->data, me->read - me->data))==HT_WOULD_BLOCK) return HT_WOULD_BLOCK; me->read = me->data; } return status; }
/* ** After flushing the buffer we go into transparent mode so that we still ** can handle incoming data. If we already are in transparent mode then ** don't do anything. */ PRIVATE int buf_flush (HTStream * me) { if (me->state != HT_BS_TRANSPARENT) { HTBufItem * cur; if (me->tmp_buf) append_buf(me); while ((cur = me->head)) { int status; if ((status = PUTBLOCK(cur->buf, cur->len)) != HT_OK) { return status; } me->head = cur->next; free_buf(cur); } /* If we are not a pipe then do no more buffering */ if ((me->mode & HT_BM_PIPE)) me->state = HT_BS_TRANSPARENT; } return (*me->target->isa->flush)(me->target); }
/* ** Searches for HTTP Request Line before going into transparent mode */ PRIVATE int HTTPReceive_put_block (HTStream * me, const char * b, int l) { if (!me->transparent) { const char *p=b; while (l>0 && *p!=CR && *p!=LF) l--, p++; HTChunk_putb(me->buffer, b, p-b); if (*p==CR || *p==LF) { int status = ParseRequest(me); HTChunk_clear(me->buffer); if (status != HT_OK) return status; me->transparent = YES; b=p; } } if (l > 0) { int status = PUTBLOCK(b, l); if (status == HT_LOADED) me->transparent = NO; return status; } return HT_OK; }
PUBLIC int HTMuxChannel_sendControl (HTMuxChannel * muxch, HTMuxSessionId sid, HTMuxHeader opcode, int value, const void * param, int param_size) { if (muxch && muxch->host) { HTOutputStream * me = HTChannel_output(HTHost_channel(muxch->host)); HTMuxHeader header[2]; switch (opcode) { case MUX_STRING: if (param && param_size) { header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value)); header[1] = HT_WORDSWAP(param_size); PUTBLOCK((const char *) header, 8); PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size)); } break; case MUX_STACK: if (param && param_size) { header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value)); header[1] = HT_WORDSWAP(param_size); PUTBLOCK((const char *) header, 8); PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size)); } break; case MUX_FRAGMENT: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_SET_SID(sid) | MUX_SET_LEN(value)); PUTBLOCK((const char *) header, 4); break; case MUX_CREDIT: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_SID(sid)); header[1] = HT_WORDSWAP(value); PUTBLOCK((const char *) header, 8); break; default: HTTRACE(MUX_TRACE, "Mux Channel. UNKNOWN OPCODE %d\n" _ opcode); return HT_ERROR; } /* Flush for now */ #if 1 return (*me->isa->flush)(me); #else return HT_OK; #endif } return HT_ERROR; }
/* HTTPMakeRequest ** --------------- ** Makes a HTTP/1.0-1.1 request header. */ PRIVATE int HTTPMakeRequest (HTStream * me, HTRequest * request) { HTMethod method = HTRequest_method(request); HTRqHd request_mask = HTRequest_rqHd(request); HTParentAnchor * anchor = HTRequest_anchor(request); char * etag = HTAnchor_etag(anchor); char crlf[3]; char qstr[10]; *crlf = CR; *(crlf+1) = LF; *(crlf+2) = '\0'; /* Generate the HTTP/1.x RequestLine */ if (me->state == 0) { if (method != METHOD_INVALID) { PUTS(HTMethod_name(method)); PUTC(' '); } else PUTS("GET "); me->state++; } /* ** Generate the Request URI. If we are using full request URI then it's ** easy. Otherwise we must filter out the path part of the URI. ** In case it's a OPTIONS request then if there is no pathinfo then use ** a * instead. If we use a method different from GET or HEAD then use ** the content-location if available. */ if (me->state == 1) { char * abs_location = NULL; char * addr = HTAnchor_physical(anchor); char * location; /* JK: If the application specified a content-location (which is stored in the request in default put-name!), we use it instead of the URL that's being saved to. This is like having a user defined Content-Location */ location = HTRequest_defaultPutName (request); if (location) { if (HTURL_isAbsolute (location)) { char * relative; relative = HTRelative (location, location); abs_location = HTParse (relative + 2, addr, PARSE_ALL); HT_FREE (relative); } else abs_location = HTParse (location, addr, PARSE_ALL); addr = abs_location; } #if 0 /* ** We don't use the content-location any more as it is superseeded ** by etags and the combination of the two might do more harm than ** good (The etag is not guaranteed to be unique over multiple URIs) */ /* ** If we are using a method different from HEAD and GET then use ** the Content-Location if available, else the Request-URI. */ if (!HTMethod_isSafe(method)) { char * location = HTAnchor_location(anchor); if (location) { if (HTURL_isAbsolute(location)) addr = location; else { /* ** We have a content-location but it is relative and ** must expand it either to the content-base or to ** the Request-URI itself. */ char * base = HTAnchor_base(anchor); abs_location = HTParse(location, base, PARSE_ALL); addr = abs_location; } } } #endif /* ** If we are using a proxy or newer versions of HTTP then we can ** send the full URL. Otherwise we only send the path. */ if (HTRequest_fullURI(request)) StrAllocCopy(me->url, addr); else { me->url = HTParse(addr, "", PARSE_PATH | PARSE_PUNCTUATION); if (method == METHOD_OPTIONS) { /* ** We don't preserve the final slash or lack of same through ** out the code. This is mainly for optimization reasons ** but it gives a problem OPTIONS. We can either send a "*" ** or a "/" but not both. For now we send a "*". */ if (!strcmp(me->url, "/")) *me->url = '*'; } } HT_FREE(abs_location); me->state++; } /* ** Now send the URL that we have put together */ if (me->state == 2) { int status = HT_OK; if ((status = PUTS(me->url)) != HT_OK) return status; me->state++; #if 0 fprintf(stderr, "Requesting '%s'\n", me->url); #endif } PUTC(' '); /* ** Send out the version number. If we know it is a HTTP/1.0 server we ** are talking to then use HTTP/1.0, else use HTTP/1.1 as default version ** number */ if (me->version == HTTP_10) PUTS(HTTP_VERSION_10); else PUTS(HTTP_VERSION); PUTBLOCK(crlf, 2); /* Request Headers */ if (request_mask & HT_C_ACCEPT_TYPE) { HTFormat format = HTRequest_outputFormat(request); /* ** If caller has specified a specific output format then use this. ** Otherwise use all the registered converters to generate the ** accept header */ if (format == WWW_PRESENT) { int list; HTList *cur; BOOL first=YES; for (list=0; list<2; list++) { if ((!list && ((cur = HTFormat_conversion()) != NULL)) || (list && ((cur = HTRequest_conversion(request))!=NULL))) { HTPresentation * pres; while ((pres=(HTPresentation *) HTList_nextObject(cur))) { if (pres->rep_out==WWW_PRESENT && pres->quality<=1.0) { if (first) { PUTS("Accept: "); first=NO; } else PUTC(','); PUTS(HTAtom_name(pres->rep)); if (pres->quality < 1.0 && pres->quality >= 0.0) { sprintf(qstr, ";q=%1.1f", pres->quality); PUTS(qstr); } } } } } if (!first) PUTBLOCK(crlf, 2); } else { /* ** If we have an explicit output format then only send ** this one if not this is an internal libwww format ** of type www/<star> */ if (!HTMIMEMatch(WWW_INTERNAL, format)) { PUTS("Accept: "); PUTS(HTAtom_name(format)); PUTBLOCK(crlf, 2); } } } if (request_mask & HT_C_ACCEPT_CHAR) { int list; HTList *cur; BOOL first=YES; for (list=0; list<2; list++) { if ((!list && ((cur = HTFormat_charset()) != NULL)) || (list && ((cur = HTRequest_charset(request)) != NULL))) { HTAcceptNode *pres; while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) { if (first) { PUTS("Accept-Charset: "); first=NO; } else PUTC(','); PUTS(HTAtom_name(pres->atom)); if (pres->quality < 1.0 && pres->quality >= 0.0) { sprintf(qstr, ";q=%1.1f", pres->quality); PUTS(qstr); } } } } if (!first) PUTBLOCK(crlf, 2); } if (request_mask & HT_C_ACCEPT_ENC) { int list; HTList *cur; BOOL first=YES; for (list=0; list<2; list++) { if ((!list && ((cur = HTFormat_contentCoding()) != NULL)) || (list && ((cur = HTRequest_encoding(request)) != NULL))) { HTCoding * pres; while ((pres = (HTCoding *) HTList_nextObject(cur))) { double quality = HTCoding_quality(pres); if (first) { PUTS("Accept-Encoding: "); first = NO; } else PUTC(','); PUTS(HTCoding_name(pres)); if (quality < 1.0 && quality >= 0.0) { sprintf(qstr, ";q=%1.1f", quality); PUTS(qstr); } } } } if (!first) PUTBLOCK(crlf, 2); } if (request_mask & HT_C_ACCEPT_TE) { int list; HTList *cur; BOOL first=YES; for (list=0; list<2; list++) { if ((!list && ((cur = HTFormat_transferCoding()) != NULL)) || (list && ((cur = HTRequest_transfer(request)) != NULL))) { HTCoding * pres; while ((pres = (HTCoding *) HTList_nextObject(cur))) { double quality = HTCoding_quality(pres); const char * coding = HTCoding_name(pres); if (first) { PUTS("TE: "); first = NO; } else PUTC(','); /* Special check for "chunked" which is translated to "trailers" */ if (!strcasecomp(coding, "chunked")) PUTS("trailers"); else PUTS(coding); if (quality < 1.0 && quality >= 0.0) { sprintf(qstr, ";q=%1.1f", quality); PUTS(qstr); } } } } if (!first) PUTBLOCK(crlf, 2); } if (request_mask & HT_C_ACCEPT_LAN) { int list; HTList *cur; BOOL first=YES; for (list=0; list<2; list++) { if ((!list && ((cur = HTFormat_language()) != NULL)) || (list && ((cur = HTRequest_language(request)) != NULL))) { HTAcceptNode *pres; while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) { if (first) { PUTS("Accept-Language: "); first=NO; } else PUTC(','); PUTS(HTAtom_name(pres->atom)); if (pres->quality < 1.0 && pres->quality >= 0.0) { sprintf(qstr, ";q=%1.1f", pres->quality); PUTS(qstr); } } } } if (!first) PUTBLOCK(crlf, 2); } if (request_mask & HT_C_AUTH) { HTAssocList * cur = HTRequest_credentials(request); if (cur) { /* Access authentication */ HTAssoc * pres; while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) { PUTS(HTAssoc_name(pres)); PUTS(": "); PUTS(HTAssoc_value(pres)); PUTBLOCK(crlf, 2); } } } if (request_mask & HT_C_EXPECT) { HTAssocList * cur = HTRequest_expect(request); if (cur) { BOOL first=YES; HTAssoc * pres; while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) { char * value = HTAssoc_value(pres); if (first) { PUTS("Expect: "); first = NO; } else PUTC(','); /* Output the name */ PUTS(HTAssoc_name(pres)); /* Only output the value if not empty string */ if (*value) { PUTS("="); PUTS(value); } } PUTBLOCK(crlf, 2); } } if (request_mask & HT_C_FROM) { HTUserProfile * up = HTRequest_userProfile(request); const char * mailaddress = HTUserProfile_email(up); if (mailaddress) { PUTS("From: "); PUTS(mailaddress); PUTBLOCK(crlf, 2); } } if (request_mask & HT_C_HOST) { char *orig = HTAnchor_address((HTAnchor *) anchor); char *host = HTParse(orig, "", PARSE_HOST); char hostace[256]; #if 0 /* Keep the port number for HTTP/1.1 compliance */ char *ptr = strchr(host, ':'); /* Chop off port number */ if (ptr) *ptr = '\0'; #endif PUTS("Host: "); /****** still have to check UTF8toACE with port number */ if (!HTACEfromUTF8 (host, hostace, 255)) { PUTS(hostace); } else { PUTS(host); /* this may be dangerous, but helps server side debugging */ HTTRACE(PROT_TRACE, "HTTP........ Error: Cannot convert to ACE: `%s\'\n" _ host); } PUTBLOCK(crlf, 2); HT_FREE(orig); HT_FREE(host); } /* ** In the "If-*" series of headers, the ones related to etags have higher ** priority than the date relates ones. That is, if we have a etag then ** use that, otherwise use the date. First we check for range, match, and ** unmodified-since. */ if (request_mask & HT_C_IF_RANGE && etag) { PUTS("If-Range: \""); PUTS(etag); PUTC('"'); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-Range using etag `%s\'\n" _ etag); } else if (request_mask & HT_C_IF_MATCH_ANY) { PUTS("If-Match: *"); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-Match using `*\'\n"); } else if (request_mask & HT_C_IF_MATCH && etag) { PUTS("If-Match: \""); PUTS(etag); PUTC('"'); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-Match using etag `%s\'\n" _ etag); } else if (request_mask & HT_C_IF_UNMOD_SINCE) { time_t lm = HTAnchor_lastModified(anchor); if (lm > 0) { PUTS("If-Unmodified-Since: "); PUTS(HTDateTimeStr(&lm, NO)); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-Unmodified-Since `%s\'\n" _ HTDateTimeStr(&lm, NO)); } } /* ** If-None-Match and If-Modified-Since are equivalent except that the ** first uses etags and the second uses dates. Etags have precedence over ** dates. */ if (request_mask & HT_C_IF_NONE_MATCH_ANY) { PUTS("If-None-Match: *"); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-None-Match using `*\'\n"); } else if (request_mask & HT_C_IF_NONE_MATCH && etag) { PUTS("If-None-Match: \""); PUTS(etag); PUTC('"'); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-None-Match `%s\'\n" _ etag); } if (request_mask & HT_C_IMS) { time_t lm = HTAnchor_lastModified(anchor); if (lm > 0) { PUTS("If-Modified-Since: "); PUTS(HTDateTimeStr(&lm, NO)); PUTBLOCK(crlf, 2); HTTRACE(PROT_TRACE, "HTTP........ If-Modified-Since `%s\'\n" _ HTDateTimeStr(&lm, NO)); } } /* ** Max forwards is mainly for TRACE where we want to be able to stop the ** TRACE at a specific location un the message path. */ if (request_mask & HT_C_MAX_FORWARDS) { int hops = HTRequest_maxForwards(request); if (hops >= 0) { sprintf(qstr, "%d", hops); PUTS("Max-Forwards: "); PUTS(qstr); PUTBLOCK(crlf, 2); } } /* ** Range requests. For now, we only take the first entry registered for ** this request. This means that you can only send a single "unit" and ** then a set of range within this unit. This is in accordance with ** HTTP/1.1. Multiple units will go on multiple lines. */ if (request_mask & HT_C_RANGE) { HTAssocList * cur = HTRequest_range(request); if (cur) { /* Range requests */ HTAssoc * pres; while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) { PUTS("Range: "); PUTS(HTAssoc_name(pres)); /* Unit */ PUTS("="); PUTS(HTAssoc_value(pres)); /* Ranges within this unit */ PUTBLOCK(crlf, 2); } } } if (request_mask & HT_C_REFERER) { HTParentAnchor * parent_anchor = HTRequest_parent(request); if (parent_anchor) { char * act = HTAnchor_address((HTAnchor *) anchor); char * parent = HTAnchor_address((HTAnchor *) parent_anchor); #if 1 char * relative = HTRelative(parent, act); #else char * relative = HTParse(parent, act, PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION); #endif if (relative && *relative) { PUTS("Referer: "); PUTS(relative); PUTBLOCK(crlf, 2); } HT_FREE(act); HT_FREE(parent); HT_FREE(relative); } } if (request_mask & HT_C_USER_AGENT) { PUTS("User-Agent: "); PUTS(HTLib_appName()); PUTC('/'); PUTS(HTLib_appVersion()); PUTC(' '); PUTS(HTLib_name()); PUTC('/'); PUTS(HTLib_version()); PUTBLOCK(crlf, 2); } HTTRACE(PROT_TRACE, "HTTP........ Generating HTTP/1.x Request Headers\n"); return HT_OK; }
PRIVATE int HTBoundary_put_block (HTStream * me, const char * b, int l) { const char *start = b; const char *end = b; while (l-- > 0) { if (me->state == EOL_FCR) { me->state = (*b == LF) ? EOL_FLF : EOL_BEGIN; } else if (me->state == EOL_FLF) { if (me->dash == 2) { while (l>0 && *me->bpos && *me->bpos==*b) l--, me->bpos++, b++; if (!*me->bpos) { HTTRACE(STREAM_TRACE, "Boundary.... `%s\' found\n" _ me->boundary); me->bpos = me->boundary; me->body = YES; me->state = EOL_DOT; } else if (l>0) { me->dash = 0; me->bpos = me->boundary; me->state = EOL_BEGIN; } } if (*b == '-') { me->dash++; } else if (*b != CR && *b != LF) { me->dash = 0; me->state = EOL_BEGIN; } } else if (me->state == EOL_SLF) { /* Look for closing '--' */ if (me->dash == 4) { if (end > start) { int status = PUTBLOCK(start, end-start); if (status != HT_OK) return status; } HTTRACE(STREAM_TRACE, "Boundary.... Ending\n"); start = b; me->dash = 0; me->state = EOL_BEGIN; } if (*b == '-') { me->dash++; } else if (*b != CR && *b != LF) { me->dash = 0; me->state = EOL_BEGIN; } me->body = NO; } else if (me->state == EOL_DOT) { int status; if (me->body) { if (me->target) FREE_TARGET; me->target = HTStreamStack(WWW_MIME,me->format, HTMerge(me->orig_target, 2), me->request, YES); if (end > start) { if ((status = PUTBLOCK(start, end-start)) != HT_OK) return status; } } else { if (me->debug) if ((status = PUTDEBUG(start, end-start)) != HT_OK) return status; } start = b; if (*b == '-') me->dash++; me->state = EOL_SLF; } else if (*b == CR) { me->state = EOL_FCR; end = b; } else if (*b == LF) { if (me->state != EOL_FCR) end = b; me->state = EOL_FLF; } b++; } return (start<b && me->body) ? PUTBLOCK(start, b-start) : HT_OK; }
PRIVATE int buf_put_block (HTStream * me, const char * b, int l) { /* ** If we are in pause mode then don't write anything but return PAUSE. ** The upper stream should then respect it and don't write any more data. */ if (me->state == HT_BS_PAUSE) return HT_PAUSE; /* ** Start handling the incoming data. If we are still buffering then add ** it to the buffer. Otherwise just pump it through. Note that we still ** count the length - even if we have given up buffering! */ me->conlen += l; if (me->state != HT_BS_TRANSPARENT) { /* ** If there is still room in the existing chunk then fill it up. ** Otherwise create a new chunk and add it to the linked list of ** chunks. If the buffer fills up then either return HT_PAUSE or ** flush it and go transparent. */ if (me->tmp_buf && me->tmp_max-me->tmp_ind >= l) { /* Still room */ memcpy(me->tmp_buf + me->tmp_ind, b, l); me->tmp_ind += l; return HT_OK; } else { /* ** Add the temporary buffer (if any) to the list of chunks */ if (me->tmp_buf) append_buf(me); /* ** Find the right size of the next chunk. We increase the size ** exponentially until we reach HT_MAX_BLOCK in order to minimize ** the number of mallocs. */ if (me->cur_size < HT_MAX_BLOCK) { int newsize = me->cur_size ? me->cur_size : HT_MIN_BLOCK; while (l > newsize && newsize < HT_MAX_BLOCK) newsize *= 2; me->cur_size = newsize; } if (alloc_new(me, me->cur_size)) { /* Buffer could accept the new data */ memcpy(me->tmp_buf, b, l); me->tmp_ind = l; } else if (me->mode & HT_BM_DELAY) { /* Buffer ran full and we pause */ me->state = HT_BS_PAUSE; HTTRACE(STREAM_TRACE, "Buffer....... Paused\n"); return HT_PAUSE; } else { /* Buffer ran full and we flush and go transparent */ int status = buf_flush(me); if (status != HT_OK) return status; } } } /* ** If we couldn't buffer the data then check whether we should give up ** or pause the stream. If we are in transparent mode then put the rest ** of the data down the pipe. */ if (me->state == HT_BS_TRANSPARENT) return PUTBLOCK(b, l); return HT_OK; }