📄 mod_isapi.c
字号:
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
*/
old_status = cid->r->status;
if (stat) {
res = ap_scan_script_header_err_strs(cid->r, NULL, &termch, &termarg,
stat, head, NULL);
}
else {
res = ap_scan_script_header_err_strs(cid->r, NULL, &termch, &termarg,
head, NULL);
}
/* Set our status. */
if (res) {
/* This is an immediate error result from the parser
*/
cid->r->status = res;
cid->r->status_line = ap_get_status_line(cid->r->status);
cid->ecb->dwHttpStatusCode = cid->r->status;
}
else if (cid->r->status) {
/* We have a status in r->status, so let's just use it.
* This is likely to be the Status: parsed above, and
* may also be a delayed error result from the parser.
* If it was filled in, status_line should also have
* been filled in.
*/
cid->ecb->dwHttpStatusCode = cid->r->status;
}
else if (cid->ecb->dwHttpStatusCode
&& cid->ecb->dwHttpStatusCode != HTTP_OK) {
/* 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 if (old_status) {
/* Well... either there is no dwHttpStatusCode or it's HTTP_OK.
* In any case, we don't have a good status to return yet...
* Perhaps the one we came in with will be better. Let's use it,
* if we were given one (note this is a pendantic case, it would
* normally be covered above unless the scan script code unset
* the r->status). Should there be a check here as to whether
* we are setting a valid response code?
*/
cid->r->status = old_status;
cid->r->status_line = ap_get_status_line(cid->r->status);
cid->ecb->dwHttpStatusCode = cid->r->status;
}
else {
/* None of dwHttpStatusCode, the parser's r->status nor the
* old value of r->status were helpful, and nothing was decoded
* from Status: string passed to us. Let's just say HTTP_OK
* and get the data out, this was the isapi dev's oversight.
*/
cid->r->status = HTTP_OK;
cid->r->status_line = ap_get_status_line(cid->r->status);
cid->ecb->dwHttpStatusCode = cid->r->status;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, cid->r,
"ISAPI: Could not determine HTTP response code; using %d",
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 = APR_SUCCESS;
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 (rv != APR_SUCCESS)
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
"ISAPI: WriteClient ap_pass_brigade "
"failed: %s", r->filename);
}
if ((flags & HSE_IO_ASYNC) && cid->completion) {
if (rv == APR_SUCCESS) {
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 == APR_SUCCESS);
}
/* A "safe" maximum bucket size, 1Gb */
#define MAX_BUCKET_SIZE (0x40000000)
apr_bucket *brigade_insert_file(apr_bucket_brigade *bb,
apr_file_t *f,
apr_off_t start,
apr_off_t length,
apr_pool_t *p)
{
apr_bucket *e;
if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) {
e = apr_bucket_file_create(f, start, (apr_size_t)length, p,
bb->bucket_alloc);
}
else {
/* Several buckets are needed. */
e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p,
bb->bucket_alloc);
while (length > MAX_BUCKET_SIZE) {
apr_bucket *ce;
apr_bucket_copy(e, &ce);
APR_BRIGADE_INSERT_TAIL(bb, ce);
e->start += MAX_BUCKET_SIZE;
length -= MAX_BUCKET_SIZE;
}
e->length = (apr_size_t)length; /* Resize just the last bucket */
}
APR_BRIGADE_INSERT_TAIL(bb, e);
return e;
}
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;
apr_status_t rv;
switch (HSE_code) {
case HSE_REQ_SEND_URL_REDIRECT_RESP:
/* Set the status to be returned when the HttpExtensionProc()
* is done.
* WARNING: Microsoft now advertises HSE_REQ_SEND_URL_REDIRECT_RESP
* and HSE_REQ_SEND_URL as equivalant per the Jan 2000 SDK.
* They most definately are not, even in their own samples.
*/
apr_table_set (r->headers_out, "Location", buf_data);
cid->r->status = cid->ecb->dwHttpStatusCode = HTTP_MOVED_TEMPORARILY;
cid->r->status_line = ap_get_status_line(cid->r->status);
cid->headers_set = 1;
return 1;
case HSE_REQ_SEND_URL:
/* Soak up remaining input */
if (r->remaining > 0) {
char argsbuffer[HUGE_STRING_LEN];
while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN));
}
/* Reset the method to GET */
r->method = apr_pstrdup(r->pool, "GET");
r->method_number = M_GET;
/* Don't let anyone think there's still data */
apr_table_unset(r->headers_in, "Content-Length");
/* AV fault per PR3598 - redirected path is lost! */
buf_data = apr_pstrdup(r->pool, (char*)buf_data);
ap_internal_redirect(buf_data, r);
return 1;
case HSE_REQ_SEND_RESPONSE_HEADER:
{
/* Parse them out, or die trying */
apr_size_t statlen = 0, headlen = 0;
apr_ssize_t ate;
if (buf_data)
statlen = strlen((char*) buf_data);
if (data_type)
headlen = strlen((char*) data_type);
ate = send_response_header(cid, (char*) buf_data,
(char*) data_type,
statlen, headlen);
if (ate < 0) {
apr_set_os_error(APR_FROM_OS_ERROR(ERROR_INVALID_PARAMETER));
return 0;
}
else if ((apr_size_t)ate < headlen) {
apr_bucket_brigade *bb;
apr_bucket *b;
bb = apr_brigade_create(cid->r->pool, c->bucket_alloc);
b = apr_bucket_transient_create((char*) data_type + ate,
headlen - 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 "
"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_DONE_WITH_SESSION:
/* Signal to resume the thread completing this request,
* leave it to the pool cleanup to dispose of our mutex.
*/
if (cid->completed) {
(void)apr_thread_mutex_unlock(cid->completed);
return 1;
}
else if (cid->dconf.log_unsupported) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"ISAPI: ServerSupportFunction "
"HSE_REQ_DONE_WITH_SESSION 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:
{
/* Map a URL to a filename */
char *file = (char *)buf_data;
apr_uint32_t len;
subreq = ap_sub_req_lookup_uri(
apr_pstrndup(cid->r->pool, file, *buf_size), r, NULL);
if (!subreq->filename) {
ap_destroy_sub_req(subreq);
return 0;
}
len = (apr_uint32_t)strlen(r->filename);
if ((subreq->finfo.filetype == APR_DIR)
&& (!subreq->path_info)
&& (file[len - 1] != '/'))
file = apr_pstrcat(cid->r->pool, subreq->filename, "/", NULL);
else
file = apr_pstrcat(cid->r->pool, subreq->filename,
subreq->path_info, NULL);
ap_destroy_sub_req(subreq);
#ifdef WIN32
/* We need to make this a real Windows path name */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -