📄 mod_isapi.c
字号:
return rv; } /* If the module was not found, it's time to create a hash key entry * before releasing the hash lock to avoid multiple threads from * loading the same module. */ key = apr_pstrdup(loaded.pool, fpath); *isa = apr_pcalloc(loaded.pool, sizeof(isapi_loaded)); (*isa)->filename = key; if (r) { /* A mutex that exists only long enough to attempt to * load this isapi dll, the release this module to all * other takers that came along during the one-time * load process. Short lifetime for this lock would * be great, however, using r->pool is nasty if those * blocked on the lock haven't all unlocked before we * attempt to destroy. A nastier race condition than * I want to deal with at this moment... */ apr_thread_rwlock_create(&(*isa)->in_progress, loaded.pool); apr_thread_rwlock_wrlock((*isa)->in_progress); } apr_hash_set(loaded.hash, key, APR_HASH_KEY_STRING, *isa); /* Now attempt to load the isapi on our own time, * allow other isapi processing to resume. */ apr_thread_mutex_unlock(loaded.lock); rv = isapi_load(loaded.pool, s, *isa); (*isa)->last_load_time = apr_time_now(); (*isa)->last_load_rv = rv; if (r && (rv == APR_SUCCESS)) { /* Let others who are blocked on this particular * module resume their requests, for better or worse. */ apr_thread_rwlock_t *unlock = (*isa)->in_progress; (*isa)->in_progress = NULL; apr_thread_rwlock_unlock(unlock); } else if (!r && (rv != APR_SUCCESS)) { /* We must leave a rwlock around for requests to retry * loading this dll after timeup... since we were in * the setup code we had avoided creating this lock. */ apr_thread_rwlock_create(&(*isa)->in_progress, loaded.pool); } return (*isa)->last_load_rv;}/********************************************************** * * ISAPI Module request callbacks section * **********************************************************//* Our "Connection ID" structure */struct isapi_cid { EXTENSION_CONTROL_BLOCK *ecb; isapi_dir_conf dconf; isapi_loaded *isa; request_rec *r; int headers_set; int response_sent; PFN_HSE_IO_COMPLETION completion; void *completion_arg; apr_thread_mutex_t *completed;};int APR_THREAD_FUNC GetServerVariable (isapi_cid *cid, char *variable_name, void *buf_ptr, apr_uint32_t *buf_size){ request_rec *r = cid->r; const char *result; char *buf_data = (char*)buf_ptr; apr_uint32_t len; if (!strcmp(variable_name, "ALL_HTTP")) { /* crlf delimited, colon split, comma separated and * null terminated list of HTTP_ vars */ const apr_array_header_t *arr = apr_table_elts(r->subprocess_env); const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts; int i; for (len = 0, i = 0; i < arr->nelts; i++) { if (!strncmp(elts[i].key, "HTTP_", 5)) { len += strlen(elts[i].key) + strlen(elts[i].val) + 3; } } if (*buf_size < len + 1) { *buf_size = len + 1; apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INSUFFICIENT_BUFFER)); return 0; } for (i = 0; i < arr->nelts; i++) { if (!strncmp(elts[i].key, "HTTP_", 5)) { strcpy(buf_data, elts[i].key); buf_data += strlen(elts[i].key); *(buf_data++) = ':'; strcpy(buf_data, elts[i].val); buf_data += strlen(elts[i].val); *(buf_data++) = '\r'; *(buf_data++) = '\n'; } } *(buf_data++) = '\0'; *buf_size = len + 1; return 1; } if (!strcmp(variable_name, "ALL_RAW")) { /* crlf delimited, colon split, comma separated and * null terminated list of the raw request header */ const apr_array_header_t *arr = apr_table_elts(r->headers_in); const apr_table_entry_t *elts = (const apr_table_entry_t *)arr->elts; int i; for (len = 0, i = 0; i < arr->nelts; i++) { len += strlen(elts[i].key) + strlen(elts[i].val) + 4; } if (*buf_size < len + 1) { *buf_size = len + 1; apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INSUFFICIENT_BUFFER)); return 0; } for (i = 0; i < arr->nelts; i++) { strcpy(buf_data, elts[i].key); buf_data += strlen(elts[i].key); *(buf_data++) = ':'; *(buf_data++) = ' '; strcpy(buf_data, elts[i].val); buf_data += strlen(elts[i].val); *(buf_data++) = '\r'; *(buf_data++) = '\n'; } *(buf_data++) = '\0'; *buf_size = len + 1; return 1; } /* Not a special case */ result = apr_table_get(r->subprocess_env, variable_name); if (result) { len = strlen(result); if (*buf_size < len + 1) { *buf_size = len + 1; apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INSUFFICIENT_BUFFER)); return 0; } strcpy(buf_data, result); *buf_size = len + 1; return 1; } /* Not Found */ apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_INDEX)); return 0;}int APR_THREAD_FUNC ReadClient(isapi_cid *cid, void *buf_data, apr_uint32_t *buf_size){ request_rec *r = cid->r; apr_uint32_t read = 0; int res; if (r->remaining < *buf_size) { *buf_size = (apr_size_t)r->remaining; } while (read < *buf_size && ((res = ap_get_client_block(r, (char*)buf_data + read, *buf_size - read)) > 0)) { read += res; } *buf_size = read; if (res < 0) { apr_set_os_error(APR_FROM_OS_ERROR(ERROR_READ_FAULT)); } return (res >= 0);}/* Common code invoked for both HSE_REQ_SEND_RESPONSE_HEADER and * the newer HSE_REQ_SEND_RESPONSE_HEADER_EX ServerSupportFunction(s) * as well as other functions that write responses and presume that * the support functions above are optional. * * Other callers trying to split headers and body bytes should pass * head/headlen alone (leaving stat/statlen NULL/0), so that they * get a proper count of bytes consumed. The argument passed to stat * isn't counted as the head bytes are. */static apr_ssize_t send_response_header(isapi_cid *cid, const char *stat, const char *head, apr_size_t statlen, apr_size_t headlen){ int head_present = 1; int termarg; const char *termch; apr_size_t ate = 0; if (!head || headlen == 0 || !*head) { head = stat; stat = NULL; headlen = statlen; statlen = 0; head_present = 0; /* Don't eat the header */ } if (!stat || statlen == 0 || !*stat) { if (head && headlen && *head && ((stat = memchr(head, '\r', headlen)) || (stat = memchr(head, '\n', headlen)) || (stat = memchr(head, '\0', headlen)) || (stat = head + headlen))) { statlen = stat - head; if (memchr(head, ':', statlen)) { stat = "Status: 200 OK"; statlen = strlen(stat); } else { const char *flip = head; head = stat; stat = flip; headlen -= statlen; ate += statlen; if (*head == '\r' && headlen) ++head, --headlen, ++ate; if (*head == '\n' && headlen) ++head, --headlen, ++ate; } } } if (stat && (statlen > 0) && *stat) { char *newstat; if (!apr_isdigit(*stat)) { const char *stattok = stat; int toklen = statlen; while (toklen && *stattok && !apr_isspace(*stattok)) { ++stattok; --toklen; } while (toklen && apr_isspace(*stattok)) { ++stattok; --toklen; } /* Now decide if we follow the xxx message * or the http/x.x xxx message format */ if (toklen && apr_isdigit(*stattok)) { statlen -= toklen; stat = stattok; } } newstat = apr_palloc(cid->r->pool, statlen + 9); strcpy(newstat, "Status: "); apr_cpystrn(newstat + 8, stat, statlen + 1); stat = newstat; statlen += 8; } if (!head || headlen == 0 || !*head) { head = "\r\n"; headlen = 2; } else { if (head[headlen - 1] && head[headlen]) { /* Whoops... not NULL terminated */ head = apr_pstrndup(cid->r->pool, head, headlen); } } /* Seems IIS does not enforce the requirement for \r\n termination * on HSE_REQ_SEND_RESPONSE_HEADER, but we won't panic... * ap_scan_script_header_err_strs handles this aspect for us. * * Parse them out, or die trying */ if (stat) { cid->r->status = ap_scan_script_header_err_strs(cid->r, NULL, &termch, &termarg, stat, head, NULL); cid->ecb->dwHttpStatusCode = cid->r->status; } else { cid->r->status = ap_scan_script_header_err_strs(cid->r, NULL, &termch, &termarg, head, NULL); if (cid->ecb->dwHttpStatusCode && cid->r->status == HTTP_OK && cid->ecb->dwHttpStatusCode != HTTP_OK) { /* We tried every way to Sunday to get the status... * so now we fall back on dwHttpStatusCode if it appears * ap_scan_script_header fell back on the default code. * Any other results set dwHttpStatusCode to the decoded * status value. */ cid->r->status = cid->ecb->dwHttpStatusCode; cid->r->status_line = ap_get_status_line(cid->r->status); } else { cid->ecb->dwHttpStatusCode = cid->r->status; } } if (cid->r->status == HTTP_INTERNAL_SERVER_ERROR) { return -1; } /* If only Status was passed, we consumed nothing */ if (!head_present) return 0; cid->headers_set = 1; /* If all went well, tell the caller we consumed the headers complete */ if (!termch) return(ate + headlen); /* Any data left must be sent directly by the caller, all we * give back is the size of the headers we consumed (which only * happens if the parser got to the head arg, which varies based * on whether we passed stat+head to scan, or only head. */ if (termch && (termarg == (stat ? 1 : 0)) && head_present && head + headlen > termch) { return ate + termch - head; } return ate;}int APR_THREAD_FUNC WriteClient(isapi_cid *cid, void *buf_ptr, apr_uint32_t *size_arg, apr_uint32_t flags){ request_rec *r = cid->r; conn_rec *c = r->connection; apr_uint32_t buf_size = *size_arg; char *buf_data = (char*)buf_ptr; apr_bucket_brigade *bb; apr_bucket *b; apr_status_t rv; if (!cid->headers_set) { /* It appears that the foxisapi module and other clients * presume that WriteClient("headers\n\nbody") will work. * Parse them out, or die trying. */ apr_ssize_t ate; ate = send_response_header(cid, NULL, buf_data, 0, buf_size); if (ate < 0) { apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; } buf_data += ate; buf_size -= ate; } if (buf_size) { bb = apr_brigade_create(r->pool, c->bucket_alloc); b = apr_bucket_transient_create(buf_data, buf_size, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_flush_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); rv = ap_pass_brigade(r->output_filters, bb); cid->response_sent = 1; } if ((flags & HSE_IO_ASYNC) && cid->completion) { if (rv == OK) { cid->completion(cid->ecb, cid->completion_arg, *size_arg, ERROR_SUCCESS); } else { cid->completion(cid->ecb, cid->completion_arg, *size_arg, ERROR_WRITE_FAULT); } } return (rv == OK);}int APR_THREAD_FUNC ServerSupportFunction(isapi_cid *cid, apr_uint32_t HSE_code, void *buf_ptr, apr_uint32_t *buf_size, apr_uint32_t *data_type){ request_rec *r = cid->r; conn_rec *c = r->connection; char *buf_data = (char*)buf_ptr; request_rec *subreq; switch (HSE_code) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -