📄 http.c
字号:
PRIVATE int HTTPStatus_flush (HTStream * me){ return (*me->target->isa->flush)(me->target);}PRIVATE int HTTPStatus_free (HTStream * me){ int status = HT_OK; if (me->target) { if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK) return HT_WOULD_BLOCK; } HT_FREE(me); return status;}PRIVATE int HTTPStatus_abort (HTStream * me, HTList * e){ if (me->target) ABORT_TARGET; HT_FREE(me); HTTRACE(PROT_TRACE, "HTTPStatus.. ABORTING...\n"); return HT_ERROR;}/* HTTPStatus Stream** -----------------*/PRIVATE const HTStreamClass HTTPStatusClass ={ "HTTPStatus", HTTPStatus_flush, HTTPStatus_free, HTTPStatus_abort, HTTPStatus_put_character, HTTPStatus_put_string, HTTPStatus_put_block};PUBLIC HTStream * HTTPStatus_new (HTRequest * request, void * param, HTFormat input_format, HTFormat output_format, HTStream * output_stream){ HTStream * me; if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL) HT_OUTOFMEM("HTTPStatus_new"); me->isa = &HTTPStatusClass; if (request) { HTNet * net = HTRequest_net(request); /* Get existing copy */ http_info * http = (http_info *) HTNet_context(net); me->request = request; me->http = http; http->next = HTTP_ERROR; me->state = EOL_BEGIN; return me; } else return HTErrorStream();}/* ------------------------------------------------------------------------- *//* Load Document from HTTP Server HTLoadHTTP** ==============================**** Given a hypertext address, this routine loads a document.**** On entry,** request This is the request structure** returns HT_ERROR Error has occured in call back** HT_OK Call back was OK*/PRIVATE int HTTPEvent (SOCKET soc, void * pVoid, HTEventType type);PUBLIC int HTLoadHTTP (SOCKET soc, HTRequest * request){ http_info *http; /* Specific protocol information */ HTParentAnchor *anchor = HTRequest_anchor(request); HTNet * net = HTRequest_net(request); /* ** Initiate a new http structure and bind to request structure ** This is actually state HTTP_BEGIN, but it can't be in the state ** machine as we need the structure first. */ HTTRACE(PROT_TRACE, "HTTP........ Looking for `%s\'\n" _ HTAnchor_physical(anchor)); if ((http = (http_info *) HT_CALLOC(1, sizeof(http_info))) == NULL) HT_OUTOFMEM("HTLoadHTTP"); http->net = net; http->request = request; HTNet_setContext(net, http); HTNet_setEventCallback(net, HTTPEvent); HTNet_setEventParam(net, http); /* callbacks get http* */ return HTTPEvent(soc, http, HTEvent_BEGIN); /* get it started - ops is ignored */}PRIVATE int FlushPutEvent (HTTimer * timer, void * param, HTEventType type){ http_info * http = (http_info *) param; HTStream * input = HTRequest_inputStream(http->request); HTPostCallback * pcbf = HTRequest_postCallback(http->request); http->usedTimer = YES; if (timer != http->timer) HTDEBUGBREAK("HTTP timer %p not in sync\n" _ timer); HTTRACE(PROT_TRACE, "Uploading... Flushing %p with timer %p\n" _ http _ timer); /* ** We ignore the return code here which we shouldn't!!! */ if (http && input && pcbf) (*pcbf)(http->request, input); /* ** Delete the timer */ HTTimer_delete(http->timer); http->timer = NULL; return HT_OK;}PRIVATE int HTTPEvent (SOCKET soc, void * pVoid, HTEventType type){ http_info * http = (http_info *)pVoid; int status = HT_ERROR; HTNet * net = http->net; HTRequest * request = HTNet_request(net); HTParentAnchor * anchor = HTRequest_anchor(request); HTHost * host = HTNet_host(net); /* ** Check whether we have been interrupted or timed out */ if (type == HTEvent_BEGIN) { http->next = HTTP_OK; http->result = HT_ERROR; } else if (type == HTEvent_CLOSE) { HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED, NULL, 0, "HTLoadHTTP"); HTTPCleanup(request, HT_INTERRUPTED); return HT_OK; } else if (type == HTEvent_TIMEOUT) { HTRequest_addError(request, ERR_FATAL, NO, HTERR_TIME_OUT, NULL, 0, "HTLoadHTTP"); HTTPCleanup(request, HT_TIMEOUT); return HT_OK; } else if (type == HTEvent_END) { HTTPCleanup(request, http->result); return HT_OK; } else if (type == HTEvent_RESET) { HTTPCleanup(request, HT_RECOVER_PIPE); http->state = HTTP_BEGIN; return HT_OK; } /* Now jump into the machine. We know the state from the previous run */ while (1) { switch (http->state) { case HTTP_BEGIN: status = HTHost_connect(host, net, HTAnchor_physical(anchor), HTTP_PORT); host = HTNet_host(net); if (status == HT_OK) { /* ** Check the protocol class to see if we have connected to a ** the right class of server, in this case HTTP. If we don't ** know the server then assume a HTTP/1.0 */ { char * s_class = HTHost_class(host); if (!s_class) { if (HTRequest_proxy(request) == NULL) { HTAssocList * alist = HTRequest_connection(request); if (!(alist && HTAssocList_findObject(alist, "close"))) HTRequest_addConnection(request, "Keep-Alive", ""); } HTHost_setClass(host, "http"); } else if (strcasecomp(s_class, "http")) { HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS, NULL, 0, "HTLoadHTTP"); http->state = HTTP_ERROR; break; } } if (ConnectionMode & HTTP_11_NO_PIPELINING) { HTTRACE(PROT_TRACE, "HTTP........ Mode is HTTP/1.1 WITH NO PIPELINING\n"); HTRequest_setFlush(request, YES); } else if (ConnectionMode & HTTP_FORCE_10) { HTTRACE(PROT_TRACE, "HTTP........ Mode is FORCE HTTP/1.0\n"); HTHost_setVersion(host, HTTP_10); } if (HTNet_preemptive(net)) { HTTRACE(PROT_TRACE, "HTTP........ Force flush on preemptive load\n"); HTRequest_setFlush(request, YES); } /* Jump to next state */ http->state = HTTP_NEED_STREAM; } else if (status == HT_WOULD_BLOCK || status == HT_PENDING) { return HT_OK; } else if (status == HT_NO_HOST) { http->result = HT_NO_HOST; http->state = HTTP_ERROR; } else http->state = HTTP_ERROR; /* Error or interrupt */ break; case HTTP_NEED_STREAM: /* ** Create the stream pipe FROM the channel to the application. ** The target for the input stream pipe is set up using the ** stream stack. */ { /* ** during a recovery, we might keep the same HTNet object. ** if so, reuse it's read stream */ HTStream * me = HTNet_readStream( net ); if ( me == NULL ) { me = HTStreamStack(WWW_HTTP, HTRequest_outputFormat(request), HTRequest_outputStream(request), request, YES);#ifdef HTDEBUG if (PROT_TRACE) { if (!htfp) htfp = fopen(HTTP_OUTPUT, "ab"); if (htfp) { me = HTTee(me, HTFWriter_new(request, htfp, YES), NULL); HTTRACE(PROT_TRACE, "HTTP........ Dumping response to `%s\'\n" _ HTTP_OUTPUT); } }#endif /* HTDEBUG */ HTNet_setReadStream(net, me); } HTRequest_setOutputConnected(request, YES); } /* ** Create the stream pipe TO the channel from the application ** and hook it up to the request object */ { HTChannel * channel = HTHost_channel(host); HTOutputStream * output = HTChannel_getChannelOStream(channel); int version = HTHost_version(host); HTStream * app = NULL; #ifdef HTDEBUG if (PROT_TRACE) { if (!htfp) htfp = fopen(HTTP_OUTPUT, "ab"); if (htfp) { output = (HTOutputStream *) HTTee((HTStream *) output, HTFWriter_new(request, htfp, YES), NULL); HTTRACE(PROT_TRACE, "HTTP........ Dumping request to `%s\'\n" _ HTTP_OUTPUT); } } #endif /* HTDEBUG */ app = HTMethod_hasEntity(HTRequest_method(request)) ? HTMIMERequest_new(request, HTTPRequest_new(request, (HTStream *) output, NO, version), YES) : HTTPRequest_new(request, (HTStream *) output, YES, version); HTRequest_setInputStream(request, app); } /* ** Set up concurrent read/write if this request isn't the ** source for a PUT or POST. As source we don't start reading ** before all destinations are ready. If destination then ** register the input stream and get ready for read */ if (HTRequest_isDestination(request)) { HTHost_register(host, net, HTEvent_READ); HTRequest_linkDestination(request); } http->state = HTTP_CONNECTED; type = HTEvent_WRITE; /* fresh, so try a write */ break; /* As we can do simultanous read and write this is now one state */ case HTTP_CONNECTED: if (type == HTEvent_WRITE) { HTStream * input = HTRequest_inputStream(request); HTPostCallback * pcbf = HTRequest_postCallback(request); status = HTRequest_flush(request) ? HTHost_forceFlush(host) : (*input->isa->flush)(input); /* ** Check to see if we are uploading something or just a normal ** GET kind of thing. */ if (pcbf) { if (http->lock == NO) { int retrys = HTRequest_retrys(request); ms_t delay = retrys > 3 ? HTSecondWriteDelay : HTFirstWriteDelay; if (!http->timer && !http->usedTimer) { http->timer = HTTimer_new(NULL, FlushPutEvent, http, delay, YES, NO); HTTRACE(PROT_TRACE, "Uploading... Holding %p for %lu ms using time %p\n" _ http _ delay _ http->timer); HTHost_register(host, net, HTEvent_READ); } http->lock = YES; } type = HTEvent_READ; } else { /* ** Check to see if we can start a new request ** pending in the host object. */ HTHost_launchPending(host); type = HTEvent_READ; } /* Now check the status code */ if (status == HT_WOULD_BLOCK) return HT_OK; else if (status == HT_PAUSE || status == HT_LOADED) { type = HTEvent_READ; } else if (status==HT_ERROR) http->state = HTTP_RECOVER_PIPE; } else if (type == HTEvent_FLUSH) { HTStream * input = HTRequest_inputStream(request); if (input == NULL) return HT_ERROR; return (*input->isa->flush)(input); } else if (type == HTEvent_READ) { status = HTHost_read(host, net); if (status == HT_WOULD_BLOCK) return HT_OK; else if (status == HT_CONTINUE) { HTTRACE(PROT_TRACE, "HTTP........ Continuing\n"); http->lock = NO; continue; } else if (status==HT_LOADED) http->state = http->next; /* Jump to next state (OK or ERROR) */ else if (status==HT_CLOSED) http->state = HTTP_RECOVER_PIPE; else if (status == HT_ERROR) http->state = HTTP_KILL_PIPE; else http->state = HTTP_ERROR; } else { http->state = HTTP_ERROR; /* don't know how to handle OOB */ } break; case HTTP_OK: HTTPCleanup(request, http->result); return HT_OK; break; case HTTP_RECOVER_PIPE: { /* ** If this is a persistent connection and we get a close ** then it is an error and we should recover from it by ** restarting the pipe line of requests if any */ if (HTHost_isPersistent(host) && !HTHost_closeNotification(host)) { if (host == NULL) return HT_ERROR; HTRequest_setFlush(request, YES); HTHost_recoverPipe(host); return HT_OK; } else http->state = HTTP_OK; } break; case HTTP_KILL_PIPE: if (host == NULL) return HT_ERROR; HTHost_killPipe(host); return HT_OK; break; case HTTP_ERROR: HTTPCleanup(request, http->result); return HT_OK; break; default: HTDEBUGBREAK("Bad http state %d\n" _ http->state); } } /* End of while(1) */} PUBLIC void HTTP_setConnectionMode (HTTPConnectionMode mode){ ConnectionMode = mode;}PUBLIC HTTPConnectionMode HTTP_connectionMode (void){ return ConnectionMode;}PUBLIC BOOL HTTP_setBodyWriteDelay (ms_t first_try, ms_t second_try){ if (first_try > 20 && second_try >= first_try) { HTFirstWriteDelay = first_try; HTSecondWriteDelay = second_try; return YES; } return NO;}PUBLIC void HTTP_bodyWriteDelay (ms_t * first_try, ms_t * second_try){ *first_try = HTFirstWriteDelay; *second_try = HTSecondWriteDelay;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -