📄 mod_isapi.c
字号:
/* Emulates a completion port... Record callback address and * user defined arg, we will call this after any async request * (e.g. transmitfile) as if the request executed async. * Per MS docs... HSE_REQ_IO_COMPLETION replaces any prior call * to HSE_REQ_IO_COMPLETION, and buf_data may be set to NULL. */ if (cid->dconf.fake_async) { cid->completion = (PFN_HSE_IO_COMPLETION) buf_data; cid->completion_arg = (void *) data_type; return 1; } if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction HSE_REQ_IO_COMPLETION " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; case HSE_REQ_TRANSMIT_FILE: { /* we do nothing with (tf->dwFlags & HSE_DISCONNECT_AFTER_SEND) */ HSE_TF_INFO *tf = (HSE_TF_INFO*)buf_data; apr_uint32_t sent = 0; apr_ssize_t ate = 0; apr_bucket_brigade *bb; apr_bucket *b; apr_file_t *fd; apr_off_t fsize; if (!cid->dconf.fake_async && (tf->dwFlags & HSE_IO_ASYNC)) { if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction HSE_REQ_TRANSMIT_FILE " "as HSE_IO_ASYNC is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; } /* Presume the handle was opened with the CORRECT semantics * for TransmitFile */ if ((rv = apr_os_file_put(&fd, &tf->hFile, APR_READ | APR_XTHREAD, r->pool)) != APR_SUCCESS) { return 0; } if (tf->BytesToWrite) { fsize = tf->BytesToWrite; } else { apr_finfo_t fi; if (apr_file_info_get(&fi, APR_FINFO_SIZE, fd) != APR_SUCCESS) { apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; } fsize = fi.size - tf->Offset; } /* apr_dupfile_oshandle (&fd, tf->hFile, r->pool); */ bb = apr_brigade_create(r->pool, c->bucket_alloc); /* According to MS: if calling HSE_REQ_TRANSMIT_FILE with the * HSE_IO_SEND_HEADERS flag, then you can't otherwise call any * HSE_SEND_RESPONSE_HEADERS* fn, but if you don't use the flag, * you must have done so. They document that the pHead headers * option is valid only for HSE_IO_SEND_HEADERS - we are a bit * more flexible and assume with the flag, pHead are the * response headers, and without, pHead simply contains text * (handled after this case). */ if ((tf->dwFlags & HSE_IO_SEND_HEADERS) && tf->pszStatusCode) { ate = send_response_header(cid, tf->pszStatusCode, (char*)tf->pHead, strlen(tf->pszStatusCode), tf->HeadLength); } else if (!cid->headers_set && tf->pHead && tf->HeadLength && *(char*)tf->pHead) { ate = send_response_header(cid, NULL, (char*)tf->pHead, 0, tf->HeadLength); if (ate < 0) { apr_brigade_destroy(bb); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; } } if (tf->pHead && (apr_size_t)ate < tf->HeadLength) { b = apr_bucket_transient_create((char*)tf->pHead + ate, tf->HeadLength - ate, c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); sent = tf->HeadLength; } sent += (apr_uint32_t)fsize; brigade_insert_file(bb, fd, tf->Offset, fsize, r->pool); if (tf->pTail && tf->TailLength) { sent += tf->TailLength; b = apr_bucket_transient_create((char*)tf->pTail, tf->TailLength, 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 (rv != APR_SUCCESS) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "ISAPI: ServerSupport function " "HSE_REQ_TRANSMIT_FILE " "ap_pass_brigade failed: %s", r->filename); /* Use tf->pfnHseIO + tf->pContext, or if NULL, then use cid->fnIOComplete * pass pContect to the HseIO callback. */ if (tf->dwFlags & HSE_IO_ASYNC) { if (tf->pfnHseIO) { if (rv == APR_SUCCESS) { tf->pfnHseIO(cid->ecb, tf->pContext, ERROR_SUCCESS, sent); } else { tf->pfnHseIO(cid->ecb, tf->pContext, ERROR_WRITE_FAULT, sent); } } else if (cid->completion) { if (rv == APR_SUCCESS) { cid->completion(cid->ecb, cid->completion_arg, sent, ERROR_SUCCESS); } else { cid->completion(cid->ecb, cid->completion_arg, sent, ERROR_WRITE_FAULT); } } } return (rv == APR_SUCCESS); } case HSE_REQ_REFRESH_ISAPI_ACL: if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction " "HSE_REQ_REFRESH_ISAPI_ACL " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; case HSE_REQ_IS_KEEP_CONN: *((int *)buf_data) = (r->connection->keepalive == AP_CONN_KEEPALIVE); return 1; case HSE_REQ_ASYNC_READ_CLIENT: { apr_uint32_t read = 0; int res; if (!cid->dconf.fake_async) { if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: asynchronous I/O not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; } 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; } if ((*data_type & HSE_IO_ASYNC) && cid->completion) { /* XXX: Many authors issue their next HSE_REQ_ASYNC_READ_CLIENT * within the completion logic. An example is MS's own PSDK * sample web/iis/extensions/io/ASyncRead. This potentially * leads to stack exhaustion. To refactor, the notification * logic needs to move to isapi_handler() - differentiating * the cid->completed event with a new flag to indicate * an async-notice versus the async request completed. */ if (res >= 0) { cid->completion(cid->ecb, cid->completion_arg, read, ERROR_SUCCESS); } else { cid->completion(cid->ecb, cid->completion_arg, read, ERROR_READ_FAULT); } } return (res >= 0); } case HSE_REQ_GET_IMPERSONATION_TOKEN: /* Added in ISAPI 4.0 */ if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction " "HSE_REQ_GET_IMPERSONATION_TOKEN " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; case HSE_REQ_MAP_URL_TO_PATH_EX: { /* Map a URL to a filename */ HSE_URL_MAPEX_INFO *info = (HSE_URL_MAPEX_INFO*)data_type; char* test_uri = apr_pstrndup(r->pool, (char *)buf_data, *buf_size); subreq = ap_sub_req_lookup_uri(test_uri, r, NULL); info->cchMatchingURL = strlen(test_uri); info->cchMatchingPath = apr_cpystrn(info->lpszPath, subreq->filename, sizeof(info->lpszPath)) - info->lpszPath; /* Mapping started with assuming both strings matched. * Now roll on the path_info as a mismatch and handle * terminating slashes for directory matches. */ if (subreq->path_info && *subreq->path_info) { apr_cpystrn(info->lpszPath + info->cchMatchingPath, subreq->path_info, sizeof(info->lpszPath) - info->cchMatchingPath); info->cchMatchingURL -= strlen(subreq->path_info); if (subreq->finfo.filetype == APR_DIR && info->cchMatchingPath < sizeof(info->lpszPath) - 1) { /* roll forward over path_info's first slash */ ++info->cchMatchingPath; ++info->cchMatchingURL; } } else if (subreq->finfo.filetype == APR_DIR && info->cchMatchingPath < sizeof(info->lpszPath) - 1) { /* Add a trailing slash for directory */ info->lpszPath[info->cchMatchingPath++] = '/'; info->lpszPath[info->cchMatchingPath] = '\0'; } /* If the matched isn't a file, roll match back to the prior slash */ if (subreq->finfo.filetype == APR_NOFILE) { while (info->cchMatchingPath && info->cchMatchingURL) { if (info->lpszPath[info->cchMatchingPath - 1] == '/') break; --info->cchMatchingPath; --info->cchMatchingURL; } } /* Paths returned with back slashes */ for (test_uri = info->lpszPath; *test_uri; ++test_uri) if (*test_uri == '/') *test_uri = '\\'; /* is a combination of: * HSE_URL_FLAGS_READ 0x001 Allow read * HSE_URL_FLAGS_WRITE 0x002 Allow write * HSE_URL_FLAGS_EXECUTE 0x004 Allow execute * HSE_URL_FLAGS_SSL 0x008 Require SSL * HSE_URL_FLAGS_DONT_CACHE 0x010 Don't cache (VRoot only) * HSE_URL_FLAGS_NEGO_CERT 0x020 Allow client SSL cert * HSE_URL_FLAGS_REQUIRE_CERT 0x040 Require client SSL cert * HSE_URL_FLAGS_MAP_CERT 0x080 Map client SSL cert to account * HSE_URL_FLAGS_SSL128 0x100 Require 128-bit SSL cert * HSE_URL_FLAGS_SCRIPT 0x200 Allow script execution * * XxX: As everywhere, EXEC flags could use some work... * and this could go further with more flags, as desired. */ info->dwFlags = (subreq->finfo.protection & APR_UREAD ? 0x001 : 0) | (subreq->finfo.protection & APR_UWRITE ? 0x002 : 0) | (subreq->finfo.protection & APR_UEXECUTE ? 0x204 : 0); return 1; } case HSE_REQ_ABORTIVE_CLOSE: if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction HSE_REQ_ABORTIVE_CLOSE" " is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; case HSE_REQ_GET_CERT_INFO_EX: /* Added in ISAPI 4.0 */ if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction " "HSE_REQ_GET_CERT_INFO_EX " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; case HSE_REQ_SEND_RESPONSE_HEADER_EX: /* Added in ISAPI 4.0 */ { HSE_SEND_HEADER_EX_INFO *shi = (HSE_SEND_HEADER_EX_INFO*)buf_data; /* Ignore shi->fKeepConn - we don't want the advise */ apr_ssize_t ate = send_response_header(cid, shi->pszStatus, shi->pszHeader, shi->cchStatus, shi->cchHeader); if (ate < 0) { apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; } else if ((apr_size_t)ate < shi->cchHeader) { apr_bucket_brigade *bb; apr_bucket *b; bb = apr_brigade_create(cid->r->pool, c->bucket_alloc); b = apr_bucket_transient_create(shi->pszHeader + ate, shi->cchHeader - ate, 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(cid->r->output_filters, bb); cid->response_sent = 1; if (rv != APR_SUCCESS) ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, "ISAPI: ServerSupport function " "HSE_REQ_SEND_RESPONSE_HEADER_EX " "ap_pass_brigade failed: %s", r->filename); return (rv == APR_SUCCESS); } /* Deliberately hold off sending 'just the headers' to begin to * accumulate the body and speed up the overall response, or at * least wait for the end the session. */ return 1; } case HSE_REQ_CLOSE_CONNECTION: /* Added after ISAPI 4.0 */ if (cid->dconf.log_unsupported) ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "ISAPI: ServerSupportFunction " "HSE_REQ_CLOSE_CONNECTION " "is not supported: %s", r->filename); apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER)); return 0; case HSE_REQ_IS_CONNECTED: /* Added after ISAPI 4.0 */ /* Returns True if client is connected c.f. MSKB Q188346 * assuming the identical return mechanism as HSE_REQ_IS_KEEP_CONN */ *((int *)buf_data) = (r->connection->aborted == 0); return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -