📄 proxy_util.c
字号:
long total_bytes_rcvd; register int n = 0, o, w; conn_rec *con = r->connection; int alternate_timeouts = 1; /* 1 if we alternate between soft & hard * timeouts */ /* allocate a buffer to store the bytes in */ /* * make sure it is at least IOBUFSIZE, as recv_buffer_size may be zero * for system default */ buf_size = MAX(recv_buffer_size, IOBUFSIZE); buf = ap_palloc(r->pool, buf_size); total_bytes_rcvd = 0; if (c != NULL) c->written = 0;#ifdef CHARSET_EBCDIC /* The cache copy is ASCII, not EBCDIC, even for text/html) */ ap_bsetflag(f, B_ASCII2EBCDIC | B_EBCDIC2ASCII, 0); ap_bsetflag(con->client, B_ASCII2EBCDIC | B_EBCDIC2ASCII, 0);#endif /* * Since we are reading from one buffer and writing to another, it is * unsafe to do a soft_timeout here, at least until the proxy has its own * timeout handler which can set both buffers to EOUT. */ ap_kill_timeout(r);#if defined(WIN32) || defined(TPF) || defined(NETWARE) /* works fine under win32, so leave it */ ap_hard_timeout("proxy send body", r); alternate_timeouts = 0;#else /* * CHECKME! Since hard_timeout won't work in unix on sends with partial * cache completion, we have to alternate between hard_timeout for reads, * and soft_timeout for send. This is because we need to get a return * from ap_bwrite to be able to continue caching. BUT, if we *can't* * continue anyway, just use hard_timeout. (Also, if no cache file is * written, use hard timeouts) */ if (c == NULL || c->len <= 0 || c->cache_completion == 1.0) { ap_hard_timeout("proxy send body", r); alternate_timeouts = 0; }#endif /* * Loop and ap_bread() while we can successfully read and write, or * (after the client aborted) while we can successfully read and finish * the configured cache_completion. */ for (end_of_chunk = ok = 1; ok;) { if (alternate_timeouts) ap_hard_timeout("proxy recv body from upstream server", r); /* read a chunked block */ if (chunked) { long chunk_start = 0; n = 0; /* start of a new chunk */ if (end_of_chunk) { end_of_chunk = 0; /* get the chunk size from the stream */ chunk_start = ap_getline(buf, buf_size, f, 0); if ((chunk_start <= 0) || ((size_t)chunk_start + 1 >= buf_size) || !ap_isxdigit(*buf)) { n = -1; } /* parse the chunk size */ else { remaining = ap_get_chunk_size(buf); if (remaining == 0) { /* Last chunk indicated, get footers */ /* as we are a proxy, we discard the footers, as the headers * have already been sent at this point. */ if (NULL == ap_proxy_read_headers(r, buf, buf_size, f)) { n = -1; } } else if (remaining < 0) { n = -1; ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r, "proxy: remote protocol error, invalid chunk size"); } } } /* read the chunk */ if (remaining > 0) { n = ap_bread(f, buf, MIN((int)buf_size, (int)remaining)); if (n > -1) { remaining -= n; end_of_chunk = (remaining == 0); } } /* soak up trailing CRLF */ if (end_of_chunk) { int ch; /* int because it may hold an EOF */ /* * For EBCDIC, the proxy has configured the BUFF layer to * transparently pass the ascii characters thru (also writing * an ASCII copy to the cache, where appropriate). * Therefore, we see here an ASCII-CRLF (\015\012), * not an EBCDIC-CRLF (\r\n). */ if ((ch = ap_bgetc(f)) == EOF) { /* Protocol error: EOF detected within chunk */ n = -1; ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r, "proxy: remote protocol error, eof while reading chunked from proxy"); } else { if (ch == '\015') { /* _ASCII_ CR */ ch = ap_bgetc(f); } if (ch != '\012') { n = -1; } } } } /* otherwise read block normally */ else { if (-1 == len) { n = ap_bread(f, buf, buf_size); } else { n = ap_bread(f, buf, MIN((int)buf_size, (int)(len - total_bytes_rcvd))); } } if (alternate_timeouts) ap_kill_timeout(r); else ap_reset_timeout(r); if (n == -1) { /* input error */ if (c != NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req, "proxy: error reading from %s", c->url); c = ap_proxy_cache_error(c); } break; } if (n == 0) break; /* EOF */ o = 0; total_bytes_rcvd += n; /* if we've received everything... */ /* * in the case of slow frontends and expensive backends, we want to * avoid leaving a backend connection hanging while the frontend * takes it's time to absorb the bytes. so: if we just read the last * block, we close the backend connection now instead of later - it's * no longer needed. */ if (total_bytes_rcvd == len) { ap_bclose(f); f = NULL; } /* Write to cache first. */ /* * @@@ XXX FIXME: Assuming that writing the cache file won't time * out?!!? */ if (c != NULL && c->fp != NULL) { if (ap_bwrite(c->fp, &buf[0], n) != n) { ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req, "proxy: error writing to %s", c->tempfile); c = ap_proxy_cache_error(c); } else { c->written += n; } } /* Write the block to the client, detect aborted transfers */ while (!nowrite && !con->aborted && n > 0) { if (alternate_timeouts) ap_soft_timeout("proxy send body", r); w = ap_bwrite(con->client, &buf[o], n); if (alternate_timeouts) ap_kill_timeout(r); else ap_reset_timeout(r); if (w <= 0) { if (c != NULL) { /* * when a send failure occurs, we need to decide whether * to continue loading and caching the document, or to * abort the whole thing */ ok = (c->len > 0) && (c->cache_completion > 0) && (c->len * c->cache_completion < total_bytes_rcvd); if (!ok) { if (c->fp != NULL) { ap_pclosef(c->req->pool, ap_bfileno(c->fp, B_WR)); c->fp = NULL; } unlink(c->tempfile); c = NULL; } } con->aborted = 1; break; } n -= w; o += w; } /* while client alive and more data to send */ /* if we've received everything, leave now */ if (total_bytes_rcvd == len) break; } /* loop and ap_bread while "ok" */ /* if the backend connection is still open, close it */ if (f) { ap_bclose(f); } if (!con->aborted) { ap_bflush(con->client); } ap_kill_timeout(r); r->bytes_sent += total_bytes_rcvd; return total_bytes_rcvd;}/* * Writes response line and headers to the cache file. * * If respline is NULL, no response line will be written. */void ap_proxy_write_headers(cache_req *c, const char *respline, table *t){ /* write status line */ if (respline && c->fp != NULL && ap_bvputs(c->fp, respline, CRLF, NULL) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req, "proxy: error writing status line to %s", c->tempfile); c = ap_proxy_cache_error(c); return; } /* write response headers to the cache file */ ap_table_do(ap_proxy_send_hdr_line, c, t, NULL); /* write terminating CRLF */ if (c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req, "proxy: error writing CRLF to %s", c->tempfile); c = ap_proxy_cache_error(c); }}/* * list is a comma-separated list of case-insensitive tokens, with * optional whitespace around the tokens. * The return returns 1 if the token val is found in the list, or 0 * otherwise. */int ap_proxy_liststr(const char *list, const char *key, char **val){ int len, i; const char *p; char valbuf[HUGE_STRING_LEN]; valbuf[sizeof(valbuf) - 1] = 0; /* safety terminating zero */ len = strlen(key); while (list != NULL) { p = strchr(list, ','); if (p != NULL) { i = p - list; do p++; while (ap_isspace(*p)); } else i = strlen(list); while (i > 0 && ap_isspace(list[i - 1])) i--; if (i == len && strncasecmp(list, key, len) == 0) { if (val) { p = strchr(list, ','); while (ap_isspace(*list)) { list++; } if ('=' == list[0]) list++; while (ap_isspace(*list)) { list++; } strncpy(valbuf, list, MIN(p - list, sizeof(valbuf) - 1)); *val = valbuf; } return 1; } list = p; } return 0;}#ifdef CASE_BLIND_FILESYSTEM/* * On some platforms, the file system is NOT case sensitive. So, a == A * need to map to smaller set of characters */void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength){ AP_MD5_CTX context; unsigned char digest[16]; char tmp[26]; int i, k, d; unsigned int x; static const char enc_table[32] = "abcdefghijklmnopqrstuvwxyz012345"; ap_MD5Init(&context); ap_MD5Update(&context, (const unsigned char *)it, strlen(it)); ap_MD5Final(digest, &context);/* encode 128 bits as 26 characters, using a modified uuencoding *//* the encoding is 5 bytes -> 8 characters * i.e. 128 bits is 3 x 5 bytes + 1 byte -> 3 * 8 characters + 2 characters */ for (i = 0, k = 0; i < 15; i += 5) { x = (digest[i] << 24) | (digest[i + 1] << 16) | (digest[i + 2] << 8) | digest[i + 3]; tmp[k++] = enc_table[x >> 27]; tmp[k++] = enc_table[(x >> 22) & 0x1f]; tmp[k++] = enc_table[(x >> 17) & 0x1f]; tmp[k++] = enc_table[(x >> 12) & 0x1f]; tmp[k++] = enc_table[(x >> 7) & 0x1f]; tmp[k++] = enc_table[(x >> 2) & 0x1f]; x = ((x & 0x3) << 8) | digest[i + 4]; tmp[k++] = enc_table[x >> 5]; tmp[k++] = enc_table[x & 0x1f]; }/* one byte left */ x = digest[15]; tmp[k++] = enc_table[x >> 3]; /* use up 5 bits */ tmp[k++] = enc_table[x & 0x7]; /* now split into directory levels */ for (i = k = d = 0; d < ndepth; ++d) { memcpy(&val[i], &tmp[k], nlength); k += nlength; val[i + nlength] = '/'; i += nlength + 1; } memcpy(&val[i], &tmp[k], 26 - k); val[i + 26 - k] = '\0';}#elsevoid ap_proxy_hash(const char *it, char *val, int ndepth, int nlength){ AP_MD5_CTX context; unsigned char digest[16]; char tmp[22]; int i, k, d; unsigned int x;#if defined(MPE) || (defined(AIX) && defined(__ps2__)) /* * Believe it or not, AIX 1.x does not allow you to name a file '@', so * hack around it in the encoding. */ static const char enc_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_%";#else static const char enc_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";#endif ap_MD5Init(&context); ap_MD5Update(&context, (const unsigned char *)it, strlen(it)); ap_MD5Final(digest, &context);/* encode 128 bits as 22 characters, using a modified uuencoding *//* the encoding is 3 bytes -> 4 characters * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters */ for (i = 0, k = 0; i < 15; i += 3) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -