📄 mod_isapi.c
字号:
apr_thread_mutex_unlock(loaded.lock); return rv; } if ((*isa)->last_load_rv == APR_SUCCESS) { apr_thread_mutex_unlock(loaded.lock); if ((rv = apr_thread_rwlock_rdlock(gainlock)) != APR_SUCCESS) { return rv; } rv = (*isa)->last_load_rv; apr_thread_rwlock_unlock(gainlock); return rv; } if (apr_time_now() > (*isa)->last_load_time + ISAPI_RETRY) { /* Remember last_load_time before releasing the global * hash lock to avoid colliding with another thread * that hit this exception at the same time as our * retry attempt, since we unlock the global mutex * before attempting a write lock for this module. */ apr_time_t check_time = (*isa)->last_load_time; apr_thread_mutex_unlock(loaded.lock); if ((rv = apr_thread_rwlock_wrlock(gainlock)) != APR_SUCCESS) { return rv; } /* If last_load_time is unchanged, we still own this * retry, otherwise presume another thread provided * our retry (for good or ill). Relock the global * hash for updating last_load_ vars, so their update * is always atomic to the global lock. */ if (check_time == (*isa)->last_load_time) { rv = isapi_load(loaded.pool, s, *isa); apr_thread_mutex_lock(loaded.lock); (*isa)->last_load_rv = rv; (*isa)->last_load_time = apr_time_now(); apr_thread_mutex_unlock(loaded.lock); } else { rv = (*isa)->last_load_rv; } apr_thread_rwlock_unlock(gainlock); return rv; } /* We haven't hit timeup on retry, let's grab the last_rv * within the hash mutex before unlocking. */ rv = (*isa)->last_load_rv; apr_thread_mutex_unlock(loaded.lock); 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; int res; int old_status; 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); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -