📄 http.c
字号:
/* HTTP.c** MULTITHREADED IMPLEMENTATION OF HTTP CLIENT**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: HTTP.c,v 1.178 1999/02/22 22:10:12 frystyk Exp $**** This module implments the HTTP protocol as a state machine**** History:** < May 24 94 ?? Unknown - but obviously written** May 24 94 HF Made reentrent and cleaned up a bit. Implemented** Forward, redirection, error handling and referer field** 8 Jul 94 FM Insulate free() from _free structure element.** Jul 94 HFN Written on top of HTTP.c, Henrik Frystyk***//* Library include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "HTHeader.h"#include "HTMIMERq.h"#include "HTReqMan.h"#include "HTTPUtil.h"#include "HTTPReq.h"#include "HTTP.h" /* Implements *//* Macros and other defines */#ifndef HTTP_PORT#define HTTP_PORT 80 /* Allocated to http by Jon Postel/ISI 24-Jan-92 */#endif#define PUTC(c) (*me->target->isa->put_character)(me->target, c)#define PUTS(s) (*me->target->isa->put_string)(me->target, s)#define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)#define FREE_TARGET (*me->target->isa->_free)(me->target)#define ABORT_TARGET (*me->target->isa->abort)(me->target, e)#ifdef HTDEBUG#include "WWWStream.h"#define HTTP_OUTPUT "w3chttp.out"PRIVATE FILE * htfp = NULL;#endif/* Type definitions and global variables etc. local to this module *//* Final states have negative value */typedef enum _HTTPState { HTTP_KILL_PIPE = -4, HTTP_RECOVER_PIPE = -3, HTTP_ERROR = -2, HTTP_OK = -1, HTTP_BEGIN = 0, HTTP_NEED_STREAM, HTTP_CONNECTED} HTTPState;/* This is the context structure for the this module */typedef struct _http_info { HTTPState state; /* Current State of the connection */ HTTPState next; /* Next state */ int result; /* Result to report to the after filter */ BOOL lock; /* Block for writing */ HTNet * net; HTRequest * request; HTTimer * timer; BOOL usedTimer;} http_info;#define MAX_STATUS_LEN 100 /* Max nb of chars to check StatusLine */struct _HTStream { const HTStreamClass * isa; HTStream * target; HTStream * info_target; /* For 100 codes */ HTRequest * request; http_info * http; HTEOLState state; BOOL transparent; BOOL cont; char * version; /* Should we save this? */ int status; char * reason; char buffer[MAX_STATUS_LEN+1]; int buflen; int startLen;/* buflen when put_block was called */};struct _HTInputStream { const HTInputStreamClass * isa;};/* How long to wait before writing the body in PUT and POST requests */#define DEFAULT_FIRST_WRITE_DELAY 2000#define DEFAULT_SECOND_WRITE_DELAY 3000PRIVATE ms_t HTFirstWriteDelay = DEFAULT_FIRST_WRITE_DELAY;PRIVATE ms_t HTSecondWriteDelay = DEFAULT_SECOND_WRITE_DELAY;#ifdef HT_NO_PIPELININGPRIVATE HTTPConnectionMode ConnectionMode = HTTP_11_NO_PIPELINING;#else#ifdef HT_MUXPRIVATE HTTPConnectionMode ConnectionMode = HTTP_11_MUX;#else#ifdef HT_FORCE_10PRIVATE HTTPConnectionMode ConnectionMode = HTTP_FORCE_10;#elsePRIVATE HTTPConnectionMode ConnectionMode = HTTP_11_PIPELINING;#endif#endif#endif/* ------------------------------------------------------------------------- *//* Help Functions *//* ------------------------------------------------------------------------- *//* HTTPCleanup** -----------** This function closes the connection and frees memory.** Returns YES on OK, else NO*/PRIVATE int HTTPCleanup (HTRequest *req, int status){ HTNet * net = HTRequest_net(req); http_info * http = (http_info *) HTNet_context(net); HTStream * input = HTRequest_inputStream(req); HTTRACE(PROT_TRACE, "HTTP Clean.. Called with status %d, net %p\n" _ status _ net); if (status == HT_INTERRUPTED) { HTAlertCallback * cbf = HTAlert_find(HT_PROG_INTERRUPT); if (cbf) (*cbf)(req, HT_PROG_INTERRUPT, HT_MSG_NULL, NULL, NULL, NULL); } else if (status == HT_TIMEOUT) { HTAlertCallback * cbf = HTAlert_find(HT_PROG_TIMEOUT); if (cbf) (*cbf)(req, HT_PROG_TIMEOUT, HT_MSG_NULL, NULL, NULL, NULL); } /* Free stream with data TO network */ if (input) { if (status==HT_INTERRUPTED || status==HT_RECOVER_PIPE || status==HT_TIMEOUT) (*input->isa->abort)(input, NULL); else (*input->isa->_free)(input); HTRequest_setInputStream(req, NULL); } /* ** Remove if we have registered an upload function as a callback */ if (http->timer) { HTTimer_delete(http->timer); http->timer = NULL; } /* ** Remove the request object and our own context structure for http. */ if (status != HT_RECOVER_PIPE) { HTNet_delete(net, status); HT_FREE(http); } return YES;}/*** Informational 1xx codes are handled separately** Returns YES if we should continue, NO if we should stop*/PRIVATE BOOL HTTPInformation (HTStream * me){ http_info * http = me->http; switch (me->status) { case 100:#if 0 HTRequest_addError(me->request, ERR_INFO, NO, HTERR_CONTINUE, me->reason, (int) strlen(me->reason), "HTTPInformation");#endif return YES; break; case 101: /* ** We consider 101 Switching as a final state and exit this request */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_SWITCHING, me->reason, (int) strlen(me->reason), "HTTPInformation"); http->next = HTTP_OK; http->result = HT_UPGRADE; break; default: HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY, (void *) me->buffer, me->buflen, "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_ERROR; break; } return NO;}/*** This is a big switch handling all HTTP return codes. It puts in any** appropiate error message and decides whether we should expect data** or not.*/PRIVATE void HTTPNextState (HTStream * me){ http_info * http = me->http; int error_class = me->status / 100; switch (error_class) { case 0: /* 0.9 response */ case 2: switch (me->status) { case 201: /* Created */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_CREATED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_CREATED; break; case 202: /* Accepted */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_ACCEPTED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_ACCEPTED; break; case 203: /* Non-authoritative information */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NON_AUTHORITATIVE, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_LOADED; break; case 204: /* No Response */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NO_CONTENT, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_NO_DATA; break; case 205: /* Reset Content */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_RESET, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_RESET_CONTENT; break; case 206: /* Partial Content */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_PARTIAL, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_PARTIAL_CONTENT; break; case 207: /* Partial Update OK */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_PARTIAL_OK, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_PARTIAL_CONTENT; break; default: HTRequest_addError(me->request, ERR_INFO, NO, HTERR_OK, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_LOADED; break; } break; case 3: switch (me->status) { case 301: /* Moved */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_MOVED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_PERM_REDIRECT; break; case 302: /* Found */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_FOUND, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_FOUND; break; case 303: /* Method */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_METHOD, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_SEE_OTHER; break; case 304: /* Not Modified */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NOT_MODIFIED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_NOT_MODIFIED; break; case 305: /* Use proxy */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_USE_PROXY, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_USE_PROXY; break; #if 0 case 306: /* Use proxy */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_PROXY_REDIRECT, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_USE_PROXY; break;#endif case 307: /* Use proxy */ HTRequest_addError(me->request, ERR_INFO, NO, HTERR_TEMP_REDIRECT, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_TEMP_REDIRECT; break; default: HTRequest_addError(me->request, ERR_INFO, NO, HTERR_MULTIPLE, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_OK; http->result = HT_LOADED; break; } break; case 4: switch (me->status) { case 401: HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_UNAUTHORIZED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_NO_ACCESS; break; case 402: /* Payment required */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_PAYMENT_REQUIRED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = -402; break; case 403: /* Forbidden */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_FORBIDDEN, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_FORBIDDEN; break; case 404: /* Not Found */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = -404; break; case 405: /* Not Allowed */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_ALLOWED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = -405; break; case 406: /* None Acceptable */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NONE_ACCEPTABLE, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_NOT_ACCEPTABLE; break; case 407: /* Proxy Authentication Required */ HTRequest_addError(me->request, ERR_FATAL, NO,HTERR_PROXY_UNAUTHORIZED, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = HT_NO_PROXY_ACCESS; break; case 408: /* Request Timeout */ HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_TIMEOUT, me->reason, (int) strlen(me->reason), "HTTPNextState"); http->next = HTTP_ERROR; http->result = -408; break; case 409: /* Conflict */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -