in modules/arch/win32/mod_isapi.c [625:805]
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);
}
}
/* 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_ex(cid->r, NULL,
APLOG_MODULE_INDEX, &termch, &termarg, stat, head, NULL);
}
else {
res = ap_scan_script_header_err_strs_ex(cid->r, NULL,
APLOG_MODULE_INDEX, &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 pedantic 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, APLOGNO(02111)
"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;
}