int uwsgi_logic_opt_for_times(char *key, char *value) { int num = atoi(uwsgi.logic_opt_data); int i; char str_num[11]; for (i = 1; i <= num; i++) { int ret = uwsgi_num2str2(i, str_num); // security check if (ret < 0 || ret > 11) { exit(1); } add_exported_option(key, uwsgi_substitute(value, "%(_)", str_num), 0); } return 1; }
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) { zmq_msg_t message; char *req_uuid = NULL; size_t req_uuid_len = 0; char *req_id = NULL; size_t req_id_len = 0; char *req_path = NULL; size_t req_path_len = 0; #ifdef UWSGI_JSON json_t *root; json_error_t error; #endif char *mongrel2_req = NULL; size_t mongrel2_req_size = 0; int resp_id_len; uint32_t events = 0; char *message_ptr; size_t message_size = 0; char *post_data; #ifdef ZMQ_EVENTS size_t events_len = sizeof(uint32_t); if (zmq_getsockopt(pthread_getspecific(wsgi_req->socket->key), ZMQ_EVENTS, &events, &events_len) < 0) { uwsgi_error("zmq_getsockopt()"); goto retry; } #endif if (events & ZMQ_POLLIN || (wsgi_req->socket->retry && wsgi_req->socket->retry[wsgi_req->async_id])) { wsgi_req->do_not_add_to_async_queue = 1; wsgi_req->proto_parser_status = 0; zmq_msg_init(&message); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_recvmsg(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #else if (zmq_recv(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #endif if (errno == EAGAIN) { zmq_msg_close(&message); goto repoll; } uwsgi_error("zmq_recv()"); zmq_msg_close(&message); goto retry; } message_size = zmq_msg_size(&message); //uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message)); if (message_size > 0xffff) { uwsgi_log("too much big message %d\n", message_size); zmq_msg_close(&message); goto retry; } message_ptr = zmq_msg_data(&message); // warning mongrel2_req_size will contains a bad value, but this is not a problem... post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (split4 phase)\n"); zmq_msg_close(&message); goto retry; } // fix post_data, mongrel2_req and mongrel2_req_size post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (body netstring phase)\n"); zmq_msg_close(&message); goto retry; } // ok ready to parse tnetstring/json data and build uwsgi request if (mongrel2_req[mongrel2_req_size] == '}') { if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) { zmq_msg_close(&message); goto retry; } } else { #ifdef UWSGI_JSON #ifdef UWSGI_DEBUG uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req); #endif // add a zero to the end of buf mongrel2_req[mongrel2_req_size] = 0; root = json_loads(mongrel2_req, 0, &error); if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); zmq_msg_close(&message); goto retry; } if (uwsgi_mongrel2_json_parse(root, wsgi_req)) { json_decref(root); zmq_msg_close(&message); goto retry; } json_decref(root); #else uwsgi_log("JSON support not enabled (recompile uWSGI with libjansson support, or re-configure mongrel2 with \"protocol='tnetstring'\". skip request\n"); #endif } // pre-build the mongrel2 response_header wsgi_req->proto_parser_buf_size = req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1; wsgi_req->proto_parser_buf = uwsgi_malloc(wsgi_req->proto_parser_buf_size); memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' '; resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':'; memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len); memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2); wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1; // handle post data (in memory) // reallocate wsgi_req->proto_parser_buf and change its size to be able to store request body // the parser status holds the current position for read_body hook if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) { if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) { char *tmp = realloc(wsgi_req->proto_parser_buf, wsgi_req->proto_parser_buf_size + wsgi_req->post_cl); if (!tmp) { uwsgi_error("realloc()"); exit(1); } wsgi_req->proto_parser_buf = tmp; // status is an offset... wsgi_req->proto_parser_status = 0; #ifdef UWSGI_DEBUG uwsgi_log("post_size: %d\n", wsgi_req->post_cl); #endif memcpy(wsgi_req->proto_parser_buf + wsgi_req->proto_parser_buf_size, message_ptr, wsgi_req->post_cl); } } zmq_msg_close(&message); // retry by default wsgi_req->socket->retry[wsgi_req->async_id] = 1; return 0; } repoll: // force polling of the socket wsgi_req->socket->retry[wsgi_req->async_id] = 0; return -1; retry: // retry til EAGAIN; wsgi_req->do_not_log = 1; wsgi_req->socket->retry[wsgi_req->async_id] = 1; return -1; } static int uwsgi_proto_zeromq_write_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { zmq_msg_t reply; if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) { uwsgi_error("uwsgi_proto_zeromq_write()/zmq_msg_init_size()"); return -1; } char *zmq_body = zmq_msg_data(&reply); memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos); if (len > 0) memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len); if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) { #else if (zmq_send(wsgi_req->socket->pub, &reply, 0)) { #endif if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); return -1; } if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); return UWSGI_OK; } int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) { int ret = uwsgi_proto_zeromq_write_do(wsgi_req, buf, len); if (ret == UWSGI_OK) { wsgi_req->write_pos += len; } return ret; }
int uwsgi_response_prepare_headers_int(struct wsgi_request *wsgi_req, int status) { char status_str[11]; uwsgi_num2str2(status, status_str); return uwsgi_response_prepare_headers(wsgi_req, status_str, 3); }
struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) { struct corerouter_session *cs = uwsgi_calloc(ucr->session_size); struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer)); // main_peer has only input buffer as output buffer is taken from backend peers size_t bufsize = ucr->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peer->in = uwsgi_buffer_new(bufsize); ucr->cr_table[new_connection] = peer; cs->main_peer = peer; peer->fd = new_connection; peer->session = cs; // map corerouter and socket cs->corerouter = ucr; cs->ugs = ugs; // set initial timeout (could be overridden) peer->current_timeout = ucr->socket_timeout; ucr->active_sessions++; // build the client address memcpy(&cs->client_sockaddr, cr_addr, cr_addr_len); switch(cr_addr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &cs->client_sockaddr.sa_in.sin_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in.sin_port, cs->client_port); break; #ifdef AF_INET6 case AF_INET6: if (inet_ntop(AF_INET6, &cs->client_sockaddr.sa_in6.sin6_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in6.sin6_port, cs->client_port); break; #endif default: memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; break; } // here we prepare the real session and set the hooks if (ucr->alloc_session(ucr, ugs, cs, cr_addr, cr_addr_len)) { corerouter_close_session(ucr, cs); cs = NULL; } else { // truly set the timeout peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]); } return cs; }
static int uwsgi_jwsgi_request(struct wsgi_request *wsgi_req) { char status_str[11]; jobject hm = NULL; jobject response = NULL; jobject r_status = NULL; jobject r_headers = NULL; jobject r_headers_entries = NULL; jobject r_body = NULL; hm = uwsgi_jvm_hashmap(); if (!hm) return -1; int i; for(i=0;i<wsgi_req->var_cnt;i++) { char *hk = wsgi_req->hvec[i].iov_base; uint16_t hk_l = wsgi_req->hvec[i].iov_len; char *hv = wsgi_req->hvec[i+1].iov_base; uint16_t hv_l = wsgi_req->hvec[i+1].iov_len; if (uwsgi_jwsgi_add_request_item(hm, hk, hk_l, hv, hv_l)) goto end; i++; } if (uwsgi_jwsgi_add_request_input(hm, "jwsgi.input", 11)) goto end; if (!ujwsgi.app_instance) { response = uwsgi_jvm_call_object_static(ujwsgi.app_class, ujwsgi.app_mid, hm); } else { response = uwsgi_jvm_call_object(ujwsgi.app_instance, ujwsgi.app_mid, hm); } if (!response) goto end; if (uwsgi_jvm_array_len(response) != 3) { uwsgi_log("invalid JWSGI response object\n"); goto end; } r_status = uwsgi_jvm_array_get(response, 0); if (!r_status) goto end; long n_status = uwsgi_jvm_number2c(r_status); if (n_status == -1) goto end; if (uwsgi_num2str2(n_status, status_str) != 3) { goto end; } if (uwsgi_response_prepare_headers(wsgi_req, status_str, 3)) goto end; r_headers = uwsgi_jvm_array_get(response, 1); if (!r_headers) goto end; // get entrySet r_headers_entries = uwsgi_jvm_entryset(r_headers); if (!r_headers_entries) goto end; // get iterator jobject values = uwsgi_jvm_auto_iterator(r_headers_entries); if (values) { int ret = uwsgi_jvm_iterator_to_response_headers(wsgi_req, values); uwsgi_jvm_local_unref(values); if (ret) goto end; } else { uwsgi_log("unsupported response headers type !!! (must be java/util/HashMap)\n"); goto end; } r_body = uwsgi_jvm_array_get(response, 2); if (!r_body) goto end; if (uwsgi_jvm_object_to_response_body(wsgi_req, r_body)) { uwsgi_log("unsupported JWSGI response body type\n"); } end: if (r_status) uwsgi_jvm_local_unref(r_status); if (r_headers_entries) uwsgi_jvm_local_unref(r_headers_entries); if (r_headers) uwsgi_jvm_local_unref(r_headers); if (r_body) uwsgi_jvm_local_unref(r_body); if (response) { uwsgi_jvm_local_unref(response); } uwsgi_jvm_local_unref(hm); return UWSGI_OK; }
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) { zmq_msg_t message; char *req_uuid = NULL; size_t req_uuid_len = 0; char *req_id = NULL; size_t req_id_len = 0; char *req_path = NULL; size_t req_path_len = 0; #ifdef UWSGI_JSON json_t *root; json_error_t error; #endif char *mongrel2_req = NULL; size_t mongrel2_req_size = 0; int resp_id_len; uint32_t events = 0; char *message_ptr; size_t message_size = 0; char *post_data; #ifdef ZMQ_EVENTS size_t events_len = sizeof(uint32_t); if (zmq_getsockopt(pthread_getspecific(wsgi_req->socket->key), ZMQ_EVENTS, &events, &events_len) < 0) { uwsgi_error("zmq_getsockopt()"); goto retry; } #endif if (events & ZMQ_POLLIN || (wsgi_req->socket->retry && wsgi_req->socket->retry[wsgi_req->async_id])) { wsgi_req->do_not_add_to_async_queue = 1; wsgi_req->proto_parser_status = 0; zmq_msg_init(&message); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_recvmsg(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #else if (zmq_recv(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #endif if (errno == EAGAIN) { zmq_msg_close(&message); goto repoll; } uwsgi_error("zmq_recv()"); zmq_msg_close(&message); goto retry; } message_size = zmq_msg_size(&message); //uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message)); if (message_size > 0xffff) { uwsgi_log("too much big message %d\n", message_size); zmq_msg_close(&message); goto retry; } message_ptr = zmq_msg_data(&message); // warning mongrel2_req_size will contains a bad value, but this is not a problem... post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (split4 phase)\n"); zmq_msg_close(&message); goto retry; } // fix post_data, mongrel2_req and mongrel2_req_size post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (body netstring phase)\n"); zmq_msg_close(&message); goto retry; } // ok ready to parse tnetstring/json data and build uwsgi request if (mongrel2_req[mongrel2_req_size] == '}') { if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) { zmq_msg_close(&message); goto retry; } } else { #ifdef UWSGI_JSON #ifdef UWSGI_DEBUG uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req); #endif // add a zero to the end of buf mongrel2_req[mongrel2_req_size] = 0; root = json_loads(mongrel2_req, 0, &error); if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); zmq_msg_close(&message); goto retry; } if (uwsgi_mongrel2_json_parse(root, wsgi_req)) { json_decref(root); zmq_msg_close(&message); goto retry; } json_decref(root); #else uwsgi_log("JSON support not enabled (recompile uWSGI with libjansson support, or re-configure mongrel2 with \"protocol='tnetstring'\". skip request\n"); #endif } // pre-build the mongrel2 response_header wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1); memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' '; resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':'; memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len); memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2); wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1; // handle post data (in memory) if (wsgi_req->post_cl > 0 && !wsgi_req->post_file) { if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) { #ifdef UWSGI_DEBUG uwsgi_log("post_size: %d\n", wsgi_req->post_cl); #endif wsgi_req->post_read_buf = uwsgi_malloc(wsgi_req->post_cl); memcpy(wsgi_req->post_read_buf, message_ptr, wsgi_req->post_cl); } } zmq_msg_close(&message); // retry by default wsgi_req->socket->retry[wsgi_req->async_id] = 1; return 0; } repoll: // force polling of the socket wsgi_req->socket->retry[wsgi_req->async_id] = 0; return -1; retry: // retry til EAGAIN; wsgi_req->do_not_log = 1; wsgi_req->socket->retry[wsgi_req->async_id] = 1; return -1; } void uwsgi_proto_zeromq_close(struct wsgi_request *wsgi_req) { zmq_msg_t reply; // check for already freed wsgi_req->proto_parser_buf/wsgi_req->proto_parser_pos if (!wsgi_req->proto_parser_pos) return; // no need to pass a free function (the buffer will be freed during cloe_request) zmq_msg_init_data(&reply, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos, NULL, NULL); if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) { uwsgi_error("uwsgi_proto_zeromq_close()/zmq_sendmsg()"); #else if (zmq_send(wsgi_req->socket->pub, &reply, 0)) { uwsgi_error("uwsgi_proto_zeromq_close()/zmq_send()"); #endif } if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); } int uwsgi_proto_zeromq_write(struct wsgi_request *wsgi_req, char *buf, size_t len) { zmq_msg_t reply; if (zmq_msg_init_size(&reply, wsgi_req->proto_parser_pos + len)) { uwsgi_error("uwsgi_proto_zeromq_write()/zmq_msg_init_size()"); return -1; } char *zmq_body = zmq_msg_data(&reply); memcpy(zmq_body, wsgi_req->proto_parser_buf, wsgi_req->proto_parser_pos); memcpy(zmq_body + wsgi_req->proto_parser_pos, buf, len); if (uwsgi.threads > 1) pthread_mutex_lock(&wsgi_req->socket->lock); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_sendmsg(wsgi_req->socket->pub, &reply, 0)) { #else if (zmq_send(wsgi_req->socket->pub, &reply, 0)) { #endif if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); return -1; } if (uwsgi.threads > 1) pthread_mutex_unlock(&wsgi_req->socket->lock); zmq_msg_close(&reply); return UWSGI_OK; } /* we have a problem... recent Mongrel2 releases introduced a ring buffer that limit the amount of messages we can send (or better, the amount of messages mongrel2 is able to manage). If we send a big static file we can fill that buffer immediately. How to deal with this ? We know that the message ring can contains a fixed amount of messages. We could try to split the file in chunks (upto the maximum number supported by a specific mongrel2 instance). This is suboptimal, but there are no better solutions for now. Before you ask: do you really think that sending a single message with a 2GB file is a good approach ????? By the way, for now, waiting for a better approach, we use a 2MB buffer. Should support flawlessly files up to 32MB without being rejected by mongrel2. For bigger files you can tune it to higher values (or increase the mongrel2 ring buffer) */ #define UWSGI_MONGREL2_MAX_MSGSIZE 2*1024*1024 int uwsgi_proto_zeromq_sendfile(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) { size_t chunk_size = UMIN( len - wsgi_req->write_pos, UWSGI_MONGREL2_MAX_MSGSIZE); char *tmp_buf = uwsgi_malloc(chunk_size); ssize_t rlen = read(fd, tmp_buf, chunk_size); if (rlen <= 0) { free(tmp_buf); return -1; } wsgi_req->write_pos += rlen; if (uwsgi_proto_zeromq_write(wsgi_req, tmp_buf, rlen) < 0) { free(tmp_buf); return -1; } free(tmp_buf); if (wsgi_req->write_pos == len) { return UWSGI_OK; } return UWSGI_AGAIN; }
ssize_t uwsgi_redis_logger(struct uwsgi_logger *ul, char *message, size_t len) { ssize_t ret,ret2; struct uwsgi_redislog_state *uredislog = NULL; if (!ul->configured) { if (!ul->data) { ul->data = uwsgi_calloc(sizeof(struct uwsgi_redislog_state)); uredislog = (struct uwsgi_redislog_state *) ul->data; } if (ul->arg != NULL) { char *logarg = uwsgi_str(ul->arg); char *comma1 = strchr(logarg, ','); if (!comma1) { uredislog->address = logarg; goto done; } *comma1 = 0; uredislog->address = logarg; comma1++; if (*comma1 == 0) goto done; char *comma2 = strchr(comma1,','); if (!comma2) { uredislog->command = uwsgi_redis_logger_build_command(comma1); goto done; } *comma2 = 0; uredislog->command = uwsgi_redis_logger_build_command(comma1); comma2++; if (*comma2 == 0) goto done; uredislog->prefix = comma2; } done: if (!uredislog->address) uredislog->address = uwsgi_str("127.0.0.1:6379"); if (!uredislog->command) uredislog->command = "*3\r\n$7\r\npublish\r\n$5\r\nuwsgi\r\n"; if (!uredislog->prefix) uredislog->prefix = ""; uredislog->fd = -1; uredislog->iovec[0].iov_base = uredislog->command; uredislog->iovec[0].iov_len = strlen(uredislog->command); uredislog->iovec[1].iov_base = "$"; uredislog->iovec[1].iov_len = 1; uredislog->iovec[2].iov_base = uredislog->msgsize; uredislog->iovec[3].iov_base = "\r\n"; uredislog->iovec[3].iov_len = 2; uredislog->iovec[4].iov_base = uredislog->prefix; uredislog->iovec[4].iov_len = strlen(uredislog->prefix); uredislog->iovec[6].iov_base = "\r\n"; uredislog->iovec[6].iov_len = 2; ul->configured = 1; } uredislog = (struct uwsgi_redislog_state *) ul->data; if (uredislog->fd == -1) { uredislog->fd = uwsgi_connect(uredislog->address, uwsgi.socket_timeout, 0); } if (uredislog->fd == -1) return -1; // drop newline if (message[len-1] == '\n') len--; uwsgi_num2str2(len + uredislog->iovec[4].iov_len, uredislog->msgsize); uredislog->iovec[2].iov_len = strlen(uredislog->msgsize); uredislog->iovec[5].iov_base = message; uredislog->iovec[5].iov_len = len; ret = writev(uredislog->fd, uredislog->iovec, 7); if (ret <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } again: // read til a \n is found (ugly but fast) ret2 = read(uredislog->fd, uredislog->response, 8); if (ret2 <= 0) { close(uredislog->fd); uredislog->fd = -1; return -1; } if (!memchr(uredislog->response, '\n', ret2)) { goto again; } return ret; }
int uwsgi_proto_zeromq_accept(struct wsgi_request *wsgi_req, int fd) { zmq_msg_t message; char *req_uuid = NULL; size_t req_uuid_len = 0; char *req_id = NULL; size_t req_id_len = 0; char *req_path = NULL; size_t req_path_len = 0; #ifdef UWSGI_JSON json_t *root; json_error_t error; #endif char *mongrel2_req = NULL; size_t mongrel2_req_size = 0; int resp_id_len; uint32_t events = 0; char *message_ptr; size_t message_size = 0; char *post_data; #ifdef ZMQ_EVENTS size_t events_len = sizeof(uint32_t); if (zmq_getsockopt(pthread_getspecific(wsgi_req->socket->key), ZMQ_EVENTS, &events, &events_len) < 0) { uwsgi_error("zmq_getsockopt()"); goto retry; } #endif if (events & ZMQ_POLLIN || (wsgi_req->socket->retry && wsgi_req->socket->retry[wsgi_req->async_id])) { wsgi_req->do_not_add_to_async_queue = 1; wsgi_req->proto_parser_status = 0; zmq_msg_init(&message); #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) if (zmq_recvmsg(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #else if (zmq_recv(pthread_getspecific(wsgi_req->socket->key), &message, wsgi_req->socket->recv_flag) < 0) { #endif if (errno == EAGAIN) { zmq_msg_close(&message); goto repoll; } uwsgi_error("zmq_recv()"); zmq_msg_close(&message); goto retry; } message_size = zmq_msg_size(&message); //uwsgi_log("%.*s\n", (int) wsgi_req->proto_parser_pos, zmq_msg_data(&message)); if (message_size > 0xffff) { uwsgi_log("too much big message %d\n", message_size); zmq_msg_close(&message); goto retry; } message_ptr = zmq_msg_data(&message); // warning mongrel2_req_size will contains a bad value, but this is not a problem... post_data = uwsgi_split4(message_ptr, message_size, ' ', &req_uuid, &req_uuid_len, &req_id, &req_id_len, &req_path, &req_path_len, &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (split4 phase)\n"); zmq_msg_close(&message); goto retry; } // fix post_data, mongrel2_req and mongrel2_req_size post_data = uwsgi_netstring(mongrel2_req, message_size - (mongrel2_req - message_ptr), &mongrel2_req, &mongrel2_req_size); if (post_data == NULL) { uwsgi_log("cannot parse message (body netstring phase)\n"); zmq_msg_close(&message); goto retry; } // ok ready to parse tnetstring/json data and build uwsgi request if (mongrel2_req[mongrel2_req_size] == '}') { if (uwsgi_mongrel2_tnetstring_parse(wsgi_req, mongrel2_req, mongrel2_req_size)) { zmq_msg_close(&message); goto retry; } } else { #ifdef UWSGI_JSON #ifdef UWSGI_DEBUG uwsgi_log("JSON %d: %.*s\n", mongrel2_req_size, mongrel2_req_size, mongrel2_req); #endif // add a zero to the end of buf mongrel2_req[mongrel2_req_size] = 0; root = json_loads(mongrel2_req, 0, &error); if (!root) { uwsgi_log("error parsing JSON data: line %d %s\n", error.line, error.text); zmq_msg_close(&message); goto retry; } if (uwsgi_mongrel2_json_parse(root, wsgi_req)) { json_decref(root); zmq_msg_close(&message); goto retry; } json_decref(root); #else uwsgi_log("JSON support not enabled (recompile uWSGI with libjansson support, or re-configure mongrel2 with \"protocol='tnetstring'\". skip request\n"); #endif } // pre-build the mongrel2 response_header wsgi_req->proto_parser_buf = uwsgi_malloc(req_uuid_len + 1 + 11 + 1 + req_id_len + 1 + 1); memcpy(wsgi_req->proto_parser_buf, req_uuid, req_uuid_len); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len] = ' '; resp_id_len = uwsgi_num2str2(req_id_len, wsgi_req->proto_parser_buf + req_uuid_len + 1); ((char *) wsgi_req->proto_parser_buf)[req_uuid_len + 1 + resp_id_len] = ':'; memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1, req_id, req_id_len); memcpy((char *) wsgi_req->proto_parser_buf + req_uuid_len + 1 + resp_id_len + 1 + req_id_len, ", ", 2); wsgi_req->proto_parser_pos = (uint64_t) req_uuid_len + 1 + resp_id_len + 1 + req_id_len + 1 + 1; // handle post data if (wsgi_req->post_cl > 0 && !wsgi_req->async_post) { if (uwsgi_netstring(post_data, message_size - (post_data - message_ptr), &message_ptr, &wsgi_req->post_cl)) { #ifdef UWSGI_DEBUG uwsgi_log("post_size: %d\n", wsgi_req->post_cl); #endif wsgi_req->async_post = tmpfile(); if (fwrite(message_ptr, wsgi_req->post_cl, 1, wsgi_req->async_post) != 1) { uwsgi_error("fwrite()"); zmq_msg_close(&message); goto retry; } rewind(wsgi_req->async_post); wsgi_req->body_as_file = 1; } } zmq_msg_close(&message); // retry by default wsgi_req->socket->retry[wsgi_req->async_id] = 1; return 0; } repoll: // force polling of the socket wsgi_req->socket->retry[wsgi_req->async_id] = 0; return -1; retry: // retry til EAGAIN; wsgi_req->do_not_log = 1; wsgi_req->socket->retry[wsgi_req->async_id] = 1; return -1; } static void uwsgi_proto_zeromq_free(void *data, void *hint) { free(data); }