PRIVATE int HTANSIReader_read (HTInputStream * me) { FILE * fp = HTChannel_file(me->ch); HTNet * net = HTHost_getReadNet(me->host); int status; /* Read the file desriptor */ while (fp) { if ((me->b_read = fread(me->data, 1, FILE_BUFFER_SIZE, fp)) == 0){ if (ferror(fp)) { HTTRACE(PROT_TRACE, "ANSI read... READ ERROR\n"); } else { HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE); HTTRACE(PROT_TRACE, "ANSI read... Finished loading file %p\n" _ fp); if (cbf) (*cbf)(net->request, HT_PROG_DONE, HT_MSG_NULL,NULL,NULL,NULL); return HT_CLOSED; } } /* Remember how much we have read from the input socket */ HTTRACEDATA(me->data, me->b_read, "HTANSIReader_read me->data:"); me->write = me->data; me->read = me->data + me->b_read; { HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ); HTNet_addBytesRead(net, me->b_read); if (cbf) { int tr = HTNet_bytesRead(net); (*cbf)(net->request, HT_PROG_READ, HT_MSG_NULL, NULL, &tr, NULL); } } /* Now push the data down the stream */ if ((status = (*net->readStream->isa->put_block) (net->readStream, me->data, me->b_read)) != HT_OK) { if (status == HT_WOULD_BLOCK) { HTTRACE(PROT_TRACE, "ANSI read... Target WOULD BLOCK\n"); return HT_WOULD_BLOCK; } else if (status == HT_PAUSE) { HTTRACE(PROT_TRACE, "ANSI read... Target PAUSED\n"); return HT_PAUSE; } else if (status > 0) { /* Stream specific return code */ HTTRACE(PROT_TRACE, "ANSI read... Target returns %d\n" _ status); me->write = me->data + me->b_read; return status; } else { /* We have a real error */ HTTRACE(PROT_TRACE, "ANSI read... Target ERROR\n"); return status; } } me->write = me->data + me->b_read; } HTTRACE(PROT_TRACE, "ANSI read... File descriptor is NULL...\n"); return HT_ERROR; }
/* ** Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF ** Folding is either of CF LWS, LF LWS, CRLF LWS */ PRIVATE int HTMIME_put_block (HTStream * me, const char * b, int l) { const char * start = b; const char * end = start; const char * value = HTChunk_size(me->value) > 0 ? b : NULL; int length = l; int status; while (!me->transparent) { if (me->EOLstate == EOL_FCR) { if (*b == CR) /* End of header */ me->EOLstate = EOL_END; else if (*b == LF) /* CRLF */ me->EOLstate = EOL_FLF; else if (isspace((int) *b)) /* Folding: CR SP */ me->EOLstate = EOL_FOLD; else /* New line */ me->EOLstate = EOL_LINE; } else if (me->EOLstate == EOL_FLF) { if (*b == CR) /* LF CR or CR LF CR */ me->EOLstate = EOL_SCR; else if (*b == LF) /* End of header */ me->EOLstate = EOL_END; else if (isspace((int) *b)) /* Folding: LF SP or CR LF SP */ me->EOLstate = EOL_FOLD; else /* New line */ me->EOLstate = EOL_LINE; } else if (me->EOLstate == EOL_SCR) { if (*b==CR || *b==LF) /* End of header */ me->EOLstate = EOL_END; else if (isspace((int) *b)) /* Folding: LF CR SP or CR LF CR SP */ me->EOLstate = EOL_FOLD; else /* New line */ me->EOLstate = EOL_LINE; } else if (*b == CR) me->EOLstate = EOL_FCR; else if (*b == LF) me->EOLstate = EOL_FLF; /* Line found */ else { if (!me->haveToken) { if (*b == ':' || isspace((int) *b)) { HTChunk_putb(me->token, start, end-start); HTChunk_putc(me->token, '\0'); me->haveToken = YES; } else { unsigned char ch = *(unsigned char *) b; ch = TOLOWER(ch); me->hash = (me->hash * 3 + ch) % MIME_HASH_SIZE; } } else if (value == NULL && *b != ':' && !isspace((int) *b)) value = b; end++; } switch (me->EOLstate) { case EOL_LINE: case EOL_END: { int ret = HT_ERROR; HTChunk_putb(me->value, value, end-value); HTChunk_putc(me->value, '\0'); ret = _stream2dispatchParsers(me); HTNet_addBytesRead(me->net, b-start); start=b, end=b; if (me->EOLstate == EOL_END) { /* EOL_END */ if (ret == HT_OK) { b++, l--; ret = pumpData(me); HTNet_addBytesRead(me->net, 1); if (me->mode & (HT_MIME_FOOTER | HT_MIME_CONT)) { HTHost_setConsumed(HTNet_host(me->net), length - l); return ret; } else { HTNet_setHeaderBytesRead(me->net, HTNet_bytesRead(me->net)); } } } else { /* EOL_LINE */ HTChunk_truncate(me->token,0); HTChunk_truncate(me->value,0); me->haveToken = NO; me->hash = 0; value = NULL; } me->EOLstate = EOL_BEGIN; if (ret != HT_OK && ret != HT_LOADED) return ret; break; } case EOL_FOLD: me->EOLstate = EOL_BEGIN; if (!me->haveToken) { HTChunk_putb(me->token, start, end-start); HTChunk_putc(me->token, '\0'); me->haveToken = YES; } else if (value) { HTChunk_putb(me->value, value, end-value); HTChunk_putc(me->value, ' '); } start=b, end=b; break; default: b++, l--; if (!l) { BOOL stop = NO; if (!me->haveToken) { /* If empty header then prepare to stop */ if (end-start) HTChunk_putb(me->token, start, end-start); else stop = YES; } else if (value) HTChunk_putb(me->value, value, end-value); HTHost_setConsumed(HTNet_host(me->net), length - l); return stop ? pumpData(me) : HT_OK; } } } if (length != l) HTHost_setConsumed(HTNet_host(me->net), length - l); /* ** Put the rest down the stream without touching the data but make sure ** that we get the correct content length of data. If we have a CL in ** the headers then this stream is responsible for the accountance. */ if (me->hasBody) { HTNet * net = me->net; /* Check if CL at all - thanks to [email protected] (John Wei) */ long cl = HTResponse_length(me->response); if (cl >= 0) { long bodyRead = HTNet_bytesRead(net) - HTNet_headerBytesRead(net); /* ** If we have more than we need then just take what belongs to us. */ if (bodyRead + l >= cl) { int consume = cl - bodyRead; if ((status = (*me->target->isa->put_block)(me->target, b, consume)) < 0) return status; else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); HTNet_addBytesRead(net, consume); HTHost_setConsumed(HTNet_host(net), consume); if (cbf) (*cbf)(me->request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); return HT_LOADED; } } else { if ((status = (*me->target->isa->put_block)(me->target, b, l)) < 0) return status; HTNet_addBytesRead(net, l); HTHost_setConsumed(HTNet_host(net), l); return status; } } return (*me->target->isa->put_block)(me->target, b, l); } else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); if (cbf) (*cbf)(me->request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); } return HT_LOADED; }
PRIVATE int HTSSLReader_read (HTInputStream * me) { HTHost * host = me->host; SOCKET soc = HTChannel_socket(me->ch); HTNet * net = HTHost_getReadNet(host); HTRequest * request = HTNet_request(net); int status; if (!net->readStream) { HTTRACE(STREAM_TRACE, "HTSSLReader. No read stream for net object %p\n" _ net); return HT_ERROR; } /* Setting SSL */ if (!me->htssl) { if ((me->htssl = HTSSL_new(soc)) == NULL) { HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO, "SSLREAD"); return HT_ERROR; } } /* Read from socket if we got rid of all the data previously read */ do { /* Don't read if we have to push unwritten data from last call */ if (me->write >= me->read) { me->b_read = 0; me->data[0] ='\0'; me->b_read = HTSSL_read(me->htssl, soc, me->data, INPUT_BUFFER_SIZE); status = HTSSL_getError(me->htssl, me->b_read); HTTRACE(STREAM_TRACE, "HTSSLReader. SSL returned %d\n" _ status); /* Check what we got done */ switch (status) { case SSL_ERROR_NONE: HTTRACEDATA(me->data, me->b_read, "Reading from socket %d" _ soc); me->write = me->data; me->read = me->data + me->b_read; HTTRACE(STREAM_TRACE, "HTSSLReader. %d bytes read from socket %d\n" _ me->b_read _ soc); /* Make progress notification */ if (request) { HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ); if (HTNet_rawBytesCount(net)) HTNet_addBytesRead(net, me->b_read); if (cbf) { int tr = HTNet_bytesRead(net); (*cbf)(request, HT_PROG_READ, HT_MSG_NULL, NULL, &tr, NULL); } } break; case SSL_ERROR_WANT_READ: HTTRACE(STREAM_TRACE, "HTSSLReader. WOULD BLOCK fd %d\n" _ soc); HTHost_register(host, net, HTEvent_READ); /* ** There seems to be a bug as even though it says "read finished" ** it doesn't say that it wants to write. We therefore have to make ** an explicit flush to make sure that we don't block forever. */ HTHost_forceFlush(host); return HT_WOULD_BLOCK; case SSL_ERROR_WANT_WRITE: return HTHost_forceFlush(host); case SSL_ERROR_WANT_X509_LOOKUP: /* @@@ what to do here? @@@ */ return HT_OK; case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_SSL: case SSL_ERROR_SYSCALL: HTTRACE(PROT_TRACE, "HTSSLReader. FIN received on socket %d\n" _ soc); HTHost_unregister(host, net, HTEvent_READ); HTHost_register(host, net, HTEvent_CLOSE); HTSSL_close(me->htssl); HTSSL_free(me->htssl); me->htssl = NULL; return HT_CLOSED; } } #ifdef FIND_SIGNATURES { char * ptr = me->data; int len = me->b_read; while ((ptr = strnstr(ptr, &len, "HTTP/1.1 200 OK")) != NULL) { HTTRACE(STREAM_TRACE, "HTSSLReader. Signature found at 0x%x of 0x%x.\n" _ ptr - me->data _ me->b_read); ptr++; len--; } } #endif /* FIND_SIGNATURES */ #ifdef NOT_ASCII { char *p = me->data; while (p < me->read) { *p = FROMASCII(*p); p++; } } #endif /* NOT_ASCII */ /* Now push the data down the stream */ if ((status = (*net->readStream->isa->put_block) (net->readStream, me->write, me->b_read)) != HT_OK) { if (status == HT_WOULD_BLOCK) { HTTRACE(STREAM_TRACE, "HTSSLReader. Target WOULD BLOCK\n"); HTHost_unregister(host, net, HTEvent_READ); return HT_WOULD_BLOCK; } else if (status == HT_PAUSE) { HTTRACE(STREAM_TRACE, "HTSSLReader. Target PAUSED\n"); HTHost_unregister(host, net, HTEvent_READ); return HT_PAUSE; /* CONTINUE code or stream code means data was consumed */ } else if (status == HT_CONTINUE || status > 0) { if (status == HT_CONTINUE) { HTTRACE(STREAM_TRACE, "HTSSLReader. CONTINUE\n"); } else HTTRACE(STREAM_TRACE, "HTSSLReader. Target returns %d\n" _ status); /* me->write = me->read; */ return status; } else { /* We have a real error */ HTTRACE(STREAM_TRACE, "HTSSLReader. Target ERROR %d\n" _ status); return status; } } me->write = me->read; { int remaining = HTHost_remainingRead(host); if (remaining > 0) { HTTRACE(STREAM_TRACE, "HTSSLReader. DIDN'T CONSUME %d BYTES: `%s\'\n" _ remaining _ me->read); HTHost_setConsumed(host, remaining); } } } while (net->preemptive); HTHost_register(host, net, HTEvent_READ); return HT_WOULD_BLOCK; }