ssize_t uwsgi_python_hook_simple_input_readline(struct wsgi_request *wsgi_req, char *readline, size_t max_size) { ssize_t rlen = 0; UWSGI_RELEASE_GIL; if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) { UWSGI_GET_GIL return 0; }
// like uwsgi_pipe but with fixed size ssize_t uwsgi_pipe_sized(int src, int dst, size_t required, int timeout) { char buf[8192]; size_t written = 0; ssize_t len; while (written < required) { int ret = uwsgi_waitfd(src, timeout); if (ret > 0) { len = read(src, buf, UMIN(8192, required - written)); if (len == 0) { return written; } else if (len < 0) { uwsgi_error("read()"); return -1; } size_t remains = len; while (remains > 0) { int ret = uwsgi_waitfd_write(dst, timeout); if (ret > 0) { len = write(dst, buf, remains); if (len > 0) { remains -= len; written += len; } else if (len == 0) { return written; } else { uwsgi_error("write()"); return -1; } } else if (ret == 0) { goto timeout; } else { return -1; } } } else if (ret == 0) { goto timeout; } else { return -1; } } return written; timeout: uwsgi_log("timeout while piping from %d to %d !!!\n", src, dst); return -1; }
int uwsgi_read_nb(int fd, char *buf, size_t remains, int timeout) { char *ptr = buf; while(remains > 0) { int ret = uwsgi_waitfd(fd, timeout); if (ret > 0) { ssize_t len = read(fd, ptr, remains); if (len <= 0) { return -1; } remains -=len; ptr +=len; continue; } return -1; } return 0; }
int uwsgi_read_uh(int fd, struct uwsgi_header *uh, int timeout) { char *ptr = (char *) uh; size_t remains = 4; while(remains > 0) { int ret = uwsgi_waitfd(fd, timeout); if (ret > 0) { ssize_t len = read(fd, ptr, remains); if (len <= 0) { return -1; } remains -=len; ptr +=len; continue; } return -1; } return 0; }
PyObject *uwsgi_Input_getline(uwsgi_Input *self) { size_t i; ssize_t rlen; struct wsgi_request *wsgi_req = self->wsgi_req; PyObject *res; char *ptr = self->readline; if (uwsgi.post_buffering > 0) { ptr = wsgi_req->post_buffering_buf; self->readline_size = wsgi_req->post_cl; if (!self->readline_pos) { self->pos += self->readline_size; } } if (self->readline_pos > 0 || uwsgi.post_buffering) { for(i=self->readline_pos;i<self->readline_size;i++) { if (ptr[i] == '\n') { res = PyString_FromStringAndSize(ptr+self->readline_pos, (i-self->readline_pos)+1); self->readline_pos = i+1; if (self->readline_pos >= self->readline_size) self->readline_pos = 0; return res; } } res = PyString_FromStringAndSize(ptr + self->readline_pos, self->readline_size - self->readline_pos); self->readline_pos = 0; return res; } UWSGI_RELEASE_GIL; if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) { UWSGI_GET_GIL return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data"); }
void uwsgi_python_harakiri(int wid) { if (up.tracebacker) { char buf[8192]; char *address = uwsgi_concat2(up.tracebacker, uwsgi_num2str(wid)); int fd = uwsgi_connect(address, -1, 0); for (;;) { int ret = uwsgi_waitfd(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); if (ret <= 0) { break; } ssize_t len = read(fd, buf, 8192); if (len <= 0) { break; } uwsgi_log("%.*s", (int) len, buf); } free(address); } }
static int uwsgi_routing_func_fcgi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = NULL, *headers = NULL; int ret = UWSGI_ROUTE_BREAK; int inbody = 0; // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_addr) return UWSGI_ROUTE_BREAK; // convert the wsgi_request to an fcgi request ub = uwsgi_to_fastcgi(wsgi_req, ur->custom ? FCGI_AUTHORIZER : FCGI_RESPONDER); if (!ub) { uwsgi_log("unable to generate fcgi request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } int fd = 0; fd = fcgi_send(wsgi_req, ub_addr->buf, ub, uwsgi.socket_timeout); uwsgi_buffer_destroy(ub); ub = NULL; if (fd == -1) { uwsgi_log("error routing request to fcgi server %s\n", ub_addr->buf); goto end; } headers = uwsgi_buffer_new(uwsgi.page_size); char buf[8192]; char *ptr = buf;//, *rptr = NULL; ssize_t left = 0, n = 0, p = 0; int oversized = 0, done = 0; for (;;) { int r = uwsgi_waitfd(fd, uwsgi.socket_timeout); if (r <= 0) goto end; ssize_t rlen = 0; /* Amount left in buffer is not a full record header, so we * need to fudge the next read to append to the current buffer. */ if ((sizeof(buf) - (ptr - buf) - left) < 8) { memmove(buf, ptr, left); ptr = buf; } if ((!done || !left) && (sizeof(buf) - (ptr - buf) - left) > 0) { rlen = read(fd, ptr + left, sizeof(buf) - (ptr - buf) - left); if (rlen < 0) break; if (rlen == 0) done = 1; } if (done && !left) { uwsgi_log("[fastcgi] %s: truncated response\n", ub_addr->buf); goto end; } if (oversized) { /* n more bytes left in stdout record */ if (uwsgi_response_write_body_do(wsgi_req, (char *) ptr, n > rlen ? rlen : n)) goto end; if (n > rlen) { n -= rlen; ptr = buf; left = 0; continue; } else if (n == rlen) { oversized = 0; left = 0; ptr = buf; continue; } else { ptr += n; left = rlen - n; oversized = 0; continue; } } else { left += rlen; } while (left >= 8 && !oversized) { if (p) { if (left >= p) { left -= p; ptr += p; p = 0; continue; } } if (ptr[0] != 1) { /* version */ uwsgi_log("[fastcgi] %s: unexpected protocol version %u\n", ub_addr->buf, (unsigned int) ptr[0]); goto end; } if (ptr[2] != 0 || ptr[3] != 1) { /* reqid */ uwsgi_log("[fastcgi] %s: unexpected request id %d\n", ub_addr->buf, (int) ptr[3]); goto end; } n = (int)((unsigned char *)ptr)[4] << 8 | (int)((unsigned char *)ptr)[5]; p = (int)((unsigned char *)ptr)[6]; int type = ptr[1]; ptr += 8; left -= 8; switch (type) { case FCGI_END_REQUEST: break; case FCGI_STDERR: uwsgi_log("[fastcgi] %s: stderr: %*s\n", ub_addr->buf, (int) (n > left ? left : n), ptr); if ((n + p) > left) { uwsgi_log("[fastcgi] %s: short record, (%d + %d) < %d\n", ub_addr->buf, (int) n, (int) p, (int) left); goto end; } ptr += (n + p); left -= (n + p); break; case FCGI_STDOUT: if (n == 0) goto end; if (!inbody) { ssize_t now = n < left ? n : left; if (uwsgi_buffer_append(headers, (char *) ptr, now)) goto end; // check if we have a full HTTP response if (uwsgi_is_full_http(headers)) { inbody = 1; if (ur->custom && http_status_code(headers->buf, headers->pos) == 200) { ret = UWSGI_ROUTE_NEXT; /* XXX - add Variable headers */ goto end; } else { uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos); } uwsgi_buffer_destroy(headers); headers = NULL; } else { /* we can't buffer > sizeof(buf) of headers - shouldn't be * needed anyway. */ if (n > left) { uwsgi_log("[fastcgi] %s: headers too long (%d)\n", ub_addr->buf, (int) n); goto end; } } ptr += now; left -= now; n -= now; } if (n) { ssize_t nleft = n > left ? left : n; /* min(left in buffer, record size) */ if (uwsgi_response_write_body_do(wsgi_req, (char *) ptr, nleft)) goto end; n -= nleft; left -= nleft; ptr += nleft; if (n > left) { /* more data in this record */ oversized = 1; left = 0; ptr = buf; continue; } } break; default: uwsgi_log("[fastcgi] %s: unknown record type %d\n", ub_addr->buf, (int) ptr[1]); goto end; } } if (left == 0) ptr = buf; } end: if (fd) close(fd); if (ub) uwsgi_buffer_destroy(ub); if (ub_addr) uwsgi_buffer_destroy(ub_addr); if (headers) uwsgi_buffer_destroy(headers); return ret; }
/* extremely complex function for reading resources (files, url...) need a lot of refactoring... */ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) { int fd; struct stat sb; char *buffer = NULL; char byte; ssize_t len; char *uri, *colon; char *domain; char *ip; int body = 0; char *magic_buf; // stdin ? if (!strcmp(url, "-")) { buffer = uwsgi_read_fd(0, size, add_zero); } // fd ? else if (!strncmp("fd://", url, 5)) { fd = atoi(url + 5); buffer = uwsgi_read_fd(fd, size, add_zero); } // exec ? else if (!strncmp("exec://", url, 5)) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("pipe()"); exit(1); } uwsgi_run_command(url + 7, NULL, cpipe[1]); buffer = uwsgi_read_fd(cpipe[0], size, add_zero); close(cpipe[0]); close(cpipe[1]); } // http url ? else if (!strncmp("http://", url, 7)) { domain = url + 7; uri = strchr(domain, '/'); if (!uri) { uwsgi_log("invalid http url\n"); exit(1); } uri[0] = 0; uwsgi_log("domain: %s\n", domain); colon = uwsgi_get_last_char(domain, ':'); if (colon) { colon[0] = 0; } ip = uwsgi_resolve_ip(domain); if (!ip) { uwsgi_log("unable to resolve address %s\n", domain); exit(1); } if (colon) { colon[0] = ':'; ip = uwsgi_concat2(ip, colon); } else { ip = uwsgi_concat2(ip, ":80"); } fd = uwsgi_connect(ip, 0, 0); if (fd < 0) { exit(1); } free(ip); uri[0] = '/'; len = write(fd, "GET ", 4); len = write(fd, uri, strlen(uri)); len = write(fd, " HTTP/1.0\r\n", 11); len = write(fd, "Host: ", 6); uri[0] = 0; len = write(fd, domain, strlen(domain)); uri[0] = '/'; len = write(fd, "\r\nUser-Agent: uWSGI on ", 23); len = write(fd, uwsgi.hostname, uwsgi.hostname_len); len = write(fd, "\r\n\r\n", 4); int http_status_code_ptr = 0; while (read(fd, &byte, 1) == 1) { if (byte == '\r' && body == 0) { body = 1; } else if (byte == '\n' && body == 1) { body = 2; } else if (byte == '\r' && body == 2) { body = 3; } else if (byte == '\n' && body == 3) { body = 4; } else if (body == 4) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = byte; } else { body = 0; http_status_code_ptr++; if (http_status_code_ptr == 10) { if (byte != '2') { uwsgi_log("Not usable HTTP response: %cxx\n", byte); if (uwsgi.has_emperor) { exit(UWSGI_EXILE_CODE); } else { exit(1); } } } } } close(fd); if (add_zero) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = 0; } } else if (!strncmp("emperor://", url, 10)) { if (uwsgi.emperor_fd_config < 0) { uwsgi_log("this is not a vassal instance\n"); exit(1); } ssize_t rlen; *size = 0; struct uwsgi_header uh; size_t remains = 4; char *ptr = (char *) &uh; while(remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config header from !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } remains = uh.pktsize; if (!remains) { uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url); exit(1); } buffer = uwsgi_calloc(remains + add_zero); ptr = buffer; while (remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config from !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } *size = uh.pktsize + add_zero; } #ifdef UWSGI_EMBED_CONFIG else if (url[0] == 0) { *size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG); } #endif else if (!strncmp("data://", url, 7)) { fd = open(uwsgi.binary_path, O_RDONLY); if (fd < 0) { uwsgi_error_open(uwsgi.binary_path); exit(1); } int slot = atoi(url + 7); if (slot < 0) { uwsgi_log("invalid binary data slot requested\n"); exit(1); } uwsgi_log("requesting binary data slot %d\n", slot); off_t fo = lseek(fd, 0, SEEK_END); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } int i = 0; uint64_t datasize = 0; for (i = 0; i <= slot; i++) { fo = lseek(fd, -9, SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } ssize_t len = read(fd, &datasize, 8); if (len != 8) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (datasize == 0) { uwsgi_log("0 size binary data !!!\n"); exit(1); } fo = lseek(fd, -(datasize + 9), SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (i == slot) { *size = datasize; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); len = read(fd, buffer, datasize); if (len != (ssize_t) datasize) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } } } } else if (!strncmp("sym://", url, 6)) { char *symbol = uwsgi_concat3("_binary_", url + 6, "_start"); void *sym_start_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_start_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); symbol = uwsgi_concat3("_binary_", url + 6, "_end"); void *sym_end_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_end_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); *size = sym_end_ptr - sym_start_ptr; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr); } #ifdef UWSGI_ELF else if (!strncmp("section://", url, 10)) { size_t s_len = 0; buffer = uwsgi_elf_section(uwsgi.binary_path, url + 10, &s_len); if (!buffer) { uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path); exit(1); } *size = s_len; if (add_zero) *size += 1; } #endif // fallback to file else { fd = open(url, O_RDONLY); if (fd < 0) { uwsgi_error_open(url); exit(1); } if (fstat(fd, &sb)) { uwsgi_error("fstat()"); exit(1); } if (S_ISFIFO(sb.st_mode)) { buffer = uwsgi_read_fd(fd, size, add_zero); close(fd); goto end; } buffer = uwsgi_malloc(sb.st_size + add_zero); len = read(fd, buffer, sb.st_size); if (len != sb.st_size) { uwsgi_error("read()"); exit(1); } close(fd); *size = sb.st_size + add_zero; if (add_zero) buffer[sb.st_size] = 0; } end: if (magic_table) { magic_buf = magic_sub(buffer, *size, size, magic_table); free(buffer); return magic_buf; } return buffer; }