📄 http_protocol.c
字号:
static int cur_method_number = METHOD_NUMBER_FIRST;/* internal function to register one method/number pair */static void register_one_method(apr_pool_t *p, const char *methname, int methnum){ int *pnum = apr_palloc(p, sizeof(*pnum)); *pnum = methnum; apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, pnum);}/* This internal function is used to clear the method registry * and reset the cur_method_number counter. */static apr_status_t ap_method_registry_destroy(void *notused){ methods_registry = NULL; cur_method_number = METHOD_NUMBER_FIRST; return APR_SUCCESS;}AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p){ methods_registry = apr_hash_make(p); apr_pool_cleanup_register(p, NULL, ap_method_registry_destroy, apr_pool_cleanup_null); /* put all the standard methods into the registry hash to ease the mapping operations between name and number */ register_one_method(p, "GET", M_GET); register_one_method(p, "PUT", M_PUT); register_one_method(p, "POST", M_POST); register_one_method(p, "DELETE", M_DELETE); register_one_method(p, "CONNECT", M_CONNECT); register_one_method(p, "OPTIONS", M_OPTIONS); register_one_method(p, "TRACE", M_TRACE); register_one_method(p, "PATCH", M_PATCH); register_one_method(p, "PROPFIND", M_PROPFIND); register_one_method(p, "PROPPATCH", M_PROPPATCH); register_one_method(p, "MKCOL", M_MKCOL); register_one_method(p, "COPY", M_COPY); register_one_method(p, "MOVE", M_MOVE); register_one_method(p, "LOCK", M_LOCK); register_one_method(p, "UNLOCK", M_UNLOCK); register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL); register_one_method(p, "CHECKOUT", M_CHECKOUT); register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT); register_one_method(p, "CHECKIN", M_CHECKIN); register_one_method(p, "UPDATE", M_UPDATE); register_one_method(p, "LABEL", M_LABEL); register_one_method(p, "REPORT", M_REPORT); register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE); register_one_method(p, "MKACTIVITY", M_MKACTIVITY); register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL); register_one_method(p, "MERGE", M_MERGE);}AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname){ int *methnum; if (methods_registry == NULL) { ap_method_registry_init(p); } if (methname == NULL) { return M_INVALID; } /* Check if the method was previously registered. If it was * return the associated method number. */ methnum = (int *)apr_hash_get(methods_registry, methname, APR_HASH_KEY_STRING); if (methnum != NULL) return *methnum; if (cur_method_number > METHOD_NUMBER_LAST) { /* The method registry has run out of dynamically * assignable method numbers. Log this and return M_INVALID. */ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, "Maximum new request methods %d reached while " "registering method %s.", METHOD_NUMBER_LAST, methname); return M_INVALID; } register_one_method(p, methname, cur_method_number); return cur_method_number++;}#define UNKNOWN_METHOD (-1)static int lookup_builtin_method(const char *method, apr_size_t len){ /* Note: the following code was generated by the "shilka" tool from the "cocom" parsing/compilation toolkit. It is an optimized lookup based on analysis of the input keywords. Postprocessing was done on the shilka output, but the basic structure and analysis is from there. Should new HTTP methods be added, then manual insertion into this code is fine, or simply re-running the shilka tool on the appropriate input. */ /* Note: it is also quite reasonable to just use our method_registry, but I'm assuming (probably incorrectly) we want more speed here (based on the optimizations the previous code was doing). */ switch (len) { case 3: switch (method[0]) { case 'P': return (method[1] == 'U' && method[2] == 'T' ? M_PUT : UNKNOWN_METHOD); case 'G': return (method[1] == 'E' && method[2] == 'T' ? M_GET : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 4: switch (method[0]) { case 'H': return (method[1] == 'E' && method[2] == 'A' && method[3] == 'D' ? M_GET : UNKNOWN_METHOD); case 'P': return (method[1] == 'O' && method[2] == 'S' && method[3] == 'T' ? M_POST : UNKNOWN_METHOD); case 'M': return (method[1] == 'O' && method[2] == 'V' && method[3] == 'E' ? M_MOVE : UNKNOWN_METHOD); case 'L': return (method[1] == 'O' && method[2] == 'C' && method[3] == 'K' ? M_LOCK : UNKNOWN_METHOD); case 'C': return (method[1] == 'O' && method[2] == 'P' && method[3] == 'Y' ? M_COPY : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 5: switch (method[2]) { case 'T': return (memcmp(method, "PATCH", 5) == 0 ? M_PATCH : UNKNOWN_METHOD); case 'R': return (memcmp(method, "MERGE", 5) == 0 ? M_MERGE : UNKNOWN_METHOD); case 'C': return (memcmp(method, "MKCOL", 5) == 0 ? M_MKCOL : UNKNOWN_METHOD); case 'B': return (memcmp(method, "LABEL", 5) == 0 ? M_LABEL : UNKNOWN_METHOD); case 'A': return (memcmp(method, "TRACE", 5) == 0 ? M_TRACE : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 6: switch (method[0]) { case 'U': switch (method[5]) { case 'K': return (memcmp(method, "UNLOCK", 6) == 0 ? M_UNLOCK : UNKNOWN_METHOD); case 'E': return (memcmp(method, "UPDATE", 6) == 0 ? M_UPDATE : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 'R': return (memcmp(method, "REPORT", 6) == 0 ? M_REPORT : UNKNOWN_METHOD); case 'D': return (memcmp(method, "DELETE", 6) == 0 ? M_DELETE : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 7: switch (method[1]) { case 'P': return (memcmp(method, "OPTIONS", 7) == 0 ? M_OPTIONS : UNKNOWN_METHOD); case 'O': return (memcmp(method, "CONNECT", 7) == 0 ? M_CONNECT : UNKNOWN_METHOD); case 'H': return (memcmp(method, "CHECKIN", 7) == 0 ? M_CHECKIN : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 8: switch (method[0]) { case 'P': return (memcmp(method, "PROPFIND", 8) == 0 ? M_PROPFIND : UNKNOWN_METHOD); case 'C': return (memcmp(method, "CHECKOUT", 8) == 0 ? M_CHECKOUT : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 9: return (memcmp(method, "PROPPATCH", 9) == 0 ? M_PROPPATCH : UNKNOWN_METHOD); case 10: switch (method[0]) { case 'U': return (memcmp(method, "UNCHECKOUT", 10) == 0 ? M_UNCHECKOUT : UNKNOWN_METHOD); case 'M': return (memcmp(method, "MKACTIVITY", 10) == 0 ? M_MKACTIVITY : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } case 11: return (memcmp(method, "MKWORKSPACE", 11) == 0 ? M_MKWORKSPACE : UNKNOWN_METHOD); case 15: return (memcmp(method, "VERSION-CONTROL", 15) == 0 ? M_VERSION_CONTROL : UNKNOWN_METHOD); case 16: return (memcmp(method, "BASELINE-CONTROL", 16) == 0 ? M_BASELINE_CONTROL : UNKNOWN_METHOD); default: return UNKNOWN_METHOD; } /* NOTREACHED */}/* Get the method number associated with the given string, assumed to * contain an HTTP method. Returns M_INVALID if not recognized. * * This is the first step toward placing method names in a configurable * list. Hopefully it (and other routines) can eventually be moved to * something like a mod_http_methods.c, complete with config stuff. */AP_DECLARE(int) ap_method_number_of(const char *method){ int len = strlen(method); int which = lookup_builtin_method(method, len); if (which != UNKNOWN_METHOD) return which; /* check if the method has been dynamically registered */ if (methods_registry != NULL) { int *methnum = apr_hash_get(methods_registry, method, len); if (methnum != NULL) { return *methnum; } } return M_INVALID;}/* * Turn a known method number into a name. */AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum){ apr_hash_index_t *hi = apr_hash_first(p, methods_registry); /* scan through the hash table, looking for a value that matches the provided method number. */ for (; hi; hi = apr_hash_next(hi)) { const void *key; void *val; apr_hash_this(hi, &key, NULL, &val); if (*(int *)val == methnum) return key; } /* it wasn't found in the hash */ return NULL;}static long get_chunk_size(char *);typedef struct http_filter_ctx { apr_off_t remaining; apr_off_t limit; apr_off_t limit_used; enum { BODY_NONE, BODY_LENGTH, BODY_CHUNK } state; int eos_sent;} http_ctx_t;/* This is the HTTP_INPUT filter for HTTP requests and responses from * proxied servers (mod_proxy). It handles chunked and content-length * bodies. This can only be inserted/used after the headers * are successfully parsed. */apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, ap_input_mode_t mode, apr_read_type_e block, apr_off_t readbytes){ apr_bucket *e; http_ctx_t *ctx = f->ctx; apr_status_t rv; apr_off_t totalread; /* just get out of the way of things we don't want. */ if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { return ap_get_brigade(f->next, b, mode, block, readbytes); } if (!ctx) { const char *tenc, *lenp; f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx)); ctx->state = BODY_NONE; ctx->remaining = 0; ctx->limit_used = 0; ctx->eos_sent = 0; /* LimitRequestBody does not apply to proxied responses. * Consider implementing this check in its own filter. * Would adding a directive to limit the size of proxied * responses be useful? */ if (!f->r->proxyreq) { ctx->limit = ap_get_limit_req_body(f->r); } else { ctx->limit = 0; } tenc = apr_table_get(f->r->headers_in, "Transfer-Encoding"); lenp = apr_table_get(f->r->headers_in, "Content-Length"); if (tenc) { if (!strcasecmp(tenc, "chunked")) { ctx->state = BODY_CHUNK; } } else if (lenp) { int conversion_error = 0; char *endstr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -