📄 srun_protocol.c
字号:
/* * Copyright (c) 1998-2001 Caucho Technology -- all rights reserved * * Caucho Technology permits redistribution, modification and use * of this file in source and binary form ("the Software") under the * Caucho Developer Source License ("the License"). The following * conditions must be met: * * 1. Each copy or derived work of the Software must preserve the copyright * notice and this notice unmodified. * * 2. Redistributions of the Software in source or binary form must include * an unmodified copy of the License, normally in a plain ASCII text * * 3. The names "Resin" or "Caucho" are trademarks of Caucho Technology and * may not be used to endorse products derived from this software. * "Resin" or "Caucho" may not appear in the names of products derived * from this software. * * 4. Caucho Technology requests that attribution be given to Resin * in any manner possible. We suggest using the "Resin Powered" * button or creating a "powered by Resin(tm)" link to * http://www.caucho.com for each page served by Resin. * * This Software is provided "AS IS," without a warranty of any kind. * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. * * CAUCHO TECHNOLOGY AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR * DISTRIBUTING SOFTWARE. IN NO EVENT WILL CAUCHO OR ITS LICENSORS BE LIABLE * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGES. * * @author Scott Ferguson */#include <linux/kernel.h>#include <linux/socket.h>#include <linux/proc_fs.h>#include <linux/in.h>#include "hardcore.h"#include "../common/srun.h"/** * Writes a string to the buffer. */static intwrite_string(char *buf, int offset, int code, char *string){ int i = offset; int len = 0; int ch; if (! string) return offset; // XXX: check total length buf[i] = code; i += 4; for (len = 0; (ch = string[len]); len++) buf[i++] = ch; buf[offset + 1] = len >> 16; buf[offset + 2] = len >> 8; buf[offset + 3] = len; return i;}/** * Writes a code packed to the buffer. */static intwrite_packet(char *buf, int offset, int code, char *data, int len){ // XXX: check total length buf[offset] = code; buf[offset + 1] = len >> 16; buf[offset + 2] = len >> 8; buf[offset + 3] = len; memcpy(buf + offset + 4, data, len); return offset + 4 + len;}/** * Writes a code packed to the buffer. */static intwrite_code(char *buf, int offset, int code){ // XXX: check total length buf[offset] = code; buf[offset + 1] = 0; buf[offset + 2] = 0; buf[offset + 3] = 0; return offset + 4;}/** * Sends a POST continuation to the servlet runner. * * Called from either RHC_SRUN_START or RHC_SRUN_POST */voidsrun_send_post(browser_t *browser){ int len = browser->request_length; int sublen = browser->cin_length - browser->cin_offset; char *data = browser->cin_buf + browser->cin_offset; int offset = 0; browser->next_state = browser->state; if (len > 0) { LOG(("sp post cl:%d cin:%d\n", len, sublen)); if (sublen == 0) { browser->state = RHC_SRUN_POST; browser_wake(browser); return; } if (sublen > len) sublen = len; if (sublen > 4096 - 8) sublen = 4096 - 8; offset = write_packet(browser->sout_buf, offset, CSE_DATA, data, sublen); len -= sublen; browser->request_length = len; browser->cin_offset += sublen; } if (len <= 0) { LOG(("sp end\n")); offset = write_code(browser->sout_buf, offset, CSE_END); } browser->sout_offset = 0; browser->sout_length = offset; browser->state = RHC_SRUN_SEND; browser_wake(browser); return;}/** * Sends the request to the servlet runner. * * Called from either RHC_SRUN_START or RHC_SRUN_POST */intresin_srun(browser_t *browser){ char *buf = browser->sout_buf; int offset = 0; int i; browser->in_header = 0; LOG(("srun %s\n", browser->url)); offset = write_string(buf, offset, CSE_METHOD, browser->method); offset = write_string(buf, offset, CSE_URI, browser->url); offset = write_string(buf, offset, CSE_PROTOCOL, browser->protocol); for (i = 0; i < browser->header_count; i++) { offset = write_string(buf, offset, CSE_HEADER, browser->key[i]); offset = write_string(buf, offset, CSE_VALUE, browser->value[i]); } if (*browser->method == 'P' && browser->request_length >= 0) { int len = browser->request_length; browser->post_offset = browser->cin_length; LOG(("post %s cl:%d cin:%d\n", browser->method, len, browser->cin_length - browser->cin_offset)); if (len <= browser->cin_length - browser->cin_offset) { char *data = browser->cin_buf + browser->cin_offset; offset = write_packet(buf, offset, CSE_DATA, data, len); browser->request_length -= len; browser->cin_offset += len; } else { char *data = browser->cin_buf + browser->cin_offset; int sublen = browser->cin_length - browser->cin_offset; offset = write_packet(buf, offset, CSE_DATA, data, sublen); browser->request_length -= sublen; browser->cin_offset += sublen; } } if (browser->request_length > 0) { browser->next_state = RHC_SRUN_RECV_HEADER; browser->state = RHC_SRUN_SEND; } else { offset = write_code(buf, offset, CSE_END); browser->next_state = RHC_SRUN_RECV_HEADER; browser->state = RHC_SRUN_SEND; } browser->sout_offset = 0; browser->sout_length = offset; return 0;}/** * Writes a string to the buffer. */static intcse_write(char *buf, int off, char *str){ while (*str) buf[off++] = *str++; return off;}/** * Proxies the headers from the srun to the browser. * * @return 1 if the browser should be rewoken */intsrun_read_header(browser_t *browser){ char *buf = browser->sin_buf; int off = browser->sin_offset; int len = browser->sin_length; int code; int packet_len = browser->packet_len; int state = browser->state; int next_state = browser->next_state; int i; char *out_buf = browser->cout_buf; int out_len = browser->cout_length; int is_done = 0; struct iovec *iov = browser->iov; int iov_index = 0; while (! is_done && off < len) { switch (state) { case RHC_SRUN_RECV_HEADER: case RHC_SRUN_BODY: // If don't have the 4 byte header, wait for more data if (len - off < 4) { if (off > 0) { for (i = len - off - 1; i >= 0; i--) buf[i] = buf[off + i]; browser->sin_offset = 0; browser->sin_length = len - off; } else { browser->sin_offset = off; browser->sin_length = len; } browser->state = state; return 1; } code = buf[off]; packet_len = (((buf[off + 1] & 0xff) << 16) + ((buf[off + 2] & 0xff) << 8) + ((buf[off + 3] & 0xff))); switch (code) { case CSE_STATUS: LOG(("status %d\n", packet_len)); state = RHC_SRUN_RECV_STATUS; off += 4; break; case CSE_HEADER: // LOG(("header %d\n", packet_len)); state = RHC_SRUN_RECV_KEY; off += 4; break; case CSE_VALUE: // LOG(("value %d\n", packet_len)); state = RHC_SRUN_RECV_VALUE; off += 4; break; case CSE_SEND_HEADER: if (browser->is_chunked) out_len = cse_write(out_buf, out_len, "Transfer-Encoding: chunked\r\n"); out_len = cse_write(out_buf, out_len, "Date: "); out_len += format_now(out_buf + out_len); out_buf[out_len++] = '\r'; out_buf[out_len++] = '\n'; out_buf[out_len++] = '\r'; out_buf[out_len++] = '\n'; LOG(("header %s %s\n", browser_state_name(browser), out_buf)); // XXX: more caching if (browser->status == 200 && browser->now < browser->expires) { cache_start(browser); } LOG(("headersdone %s time-delta:%d\n", browser_state_name(browser), browser->now - browser->expires)); state = RHC_SRUN_BODY; off += 4; iov[0].iov_base = out_buf; iov[0].iov_len = out_len; iov_index = 1; break; case CSE_DATA: LOG(("data %d\n", packet_len)); off += 4; state = RHC_SRUN_RECV_DATA; if (browser->is_chunked && packet_len > 0) { } break; case CSE_ACK: LOG(("ack %d\n", packet_len)); off += 4; browser->state = state; browser->next_state = next_state; srun_send_post(browser); state = browser->state; next_state = browser->next_state; is_done = 1; break; case CSE_END: case CSE_CLOSE: LOG(("quit %d\n", packet_len)); state = RHC_BROWSER_QUIT; off += 4; is_done = 1; if (browser->cache) cache_finish(browser); break; default: LOG(("skip %c %d\n", code, packet_len)); off += 4; if (packet_len > 0) { next_state = state; state = RHC_SRUN_RECV_SKIP; } break; } break; case RHC_SRUN_RECV_STATUS: out_len = 0; browser->cout_length = 0; browser->cout_offset = 0; // XXX: must restrict length for (; packet_len > 0 && off < len; packet_len--, off++) out_buf[out_len++] = buf[off]; if (packet_len <= 0) { // HTTP/1.x nnn msg browser->status = (100 * (out_buf[9] - '0') + 10 * (out_buf[10] - '0') + out_buf[11] - '0'); out_buf[out_len++] = '\r'; out_buf[out_len++] = '\n'; out_buf[out_len] = 0; if (browser->version == HTTP_1_1) { browser->is_chunked = out_buf[7] == '1'; if (! browser->keepalive) out_len = cse_write(out_buf, out_len, "Connection: close\r\n"); } else browser->is_chunked = 0; out_len = cse_write(out_buf, out_len, "Server: ResinHardCore/1.3\r\n"); out_buf[out_len] = 0; state = RHC_SRUN_RECV_HEADER; browser->key_start = out_buf + out_len; } break; case RHC_SRUN_RECV_KEY: // XXX: must restrict length for (; packet_len > 0 && off < len; packet_len--, off++) out_buf[out_len++] = buf[off]; if (packet_len <= 0) { out_buf[out_len++] = ':'; out_buf[out_len++] = ' '; out_buf[out_len] = 0; // LOG(("key %s\n", browser->key_start)); browser->value_start = out_buf + out_len; state = RHC_SRUN_RECV_HEADER; } break; case RHC_SRUN_RECV_VALUE: // XXX: must restrict length for (; packet_len > 0 && off < len; packet_len--, off++) out_buf[out_len++] = buf[off]; if (packet_len <= 0) { char *key = browser->key_start; out_buf[out_len++] = '\r'; out_buf[out_len++] = '\n'; out_buf[out_len] = 0; LOG(("%s", browser->key_start)); switch (*key) { case 'e': case 'E': if (strnicmp(key, "Expires:", 8)) { browser->expires = parse_date(browser->value_start); LOG(("Expires %d\n", browser->expires)); } break; case 'c': case 'C': if (! strnicmp(key, "Content-Length:", sizeof("Context-Length:"))) browser->is_chunked = 0; break; } state = RHC_SRUN_RECV_HEADER; browser->key_start = out_buf + out_len; } break; case RHC_SRUN_RECV_DATA: LOG(("recv-data %d %d\n", packet_len, len - off)); if (packet_len <= len - off) { iov[iov_index].iov_base = buf + off; iov[iov_index].iov_len = packet_len; off += packet_len; state = RHC_SRUN_BODY; } else { iov[iov_index].iov_base = buf + off; iov[iov_index].iov_len = len - off; packet_len -= len - off; off = len; } if (browser->cache) cache_write(browser, iov[iov_index].iov_base, iov[iov_index].iov_len); iov_index++; break; case RHC_SRUN_RECV_SKIP: if (packet_len < len - off) { off += packet_len; state = next_state; } else { packet_len -= len - off; off = len; } break; default: is_done = 1; break; } } LOG(("done %d %d\n", off, len)); if (off < len) { browser->sin_offset = off; browser->sin_length = len; } else { browser->sin_offset = 0; browser->sin_length = 0; } browser->cout_length = out_len; browser->packet_len = packet_len; browser->state = state; browser->next_state = next_state; if (iov_index > 0) { browser->write_state = state; browser->state = RHC_BROWSER_WRITE; browser->iov_index = iov_index; return browser_write_iov(browser) > 0; } else return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -