Beispiel #1
0
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
#ifdef UWSGI_SSL
	char sha1[20];
	if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
	if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
	if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
        if (origin_len > 0) {
		if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
        }
        else {
		if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
        }
	// generate websockets sha1 and encode it to base64
        if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
	size_t b64_len = 0;
        char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
	if (!b64) return -1;

	if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
		free(b64);
		return -1;
	}
	free(b64);

	wsgi_req->websocket_last_pong = uwsgi_now();

	return uwsgi_response_write_headers_do(wsgi_req);
#else
	uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
	return -1;
#endif
}
Beispiel #2
0
// this is the function called by all request plugins to send chunks to the client
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {

	if (wsgi_req->write_errors) return -1;

	if (!wsgi_req->headers_sent) {
		int ret = uwsgi_response_write_headers_do(wsgi_req);
                if (ret == UWSGI_OK) goto sendbody;
                if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
		wsgi_req->write_errors++;
                return -1;
	}

sendbody:

	if (len == 0) return UWSGI_OK;

	for(;;) {
		int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
		if (ret < 0) {
			if (!uwsgi.ignore_write_errors) {
				uwsgi_error("uwsgi_response_write_body_do()");
			}
			wsgi_req->write_errors++;
			return -1;
		}
		if (ret == UWSGI_OK) {
			break;
		}
		ret = uwsgi_wait_write_req(wsgi_req);			
		if (ret < 0) { wsgi_req->write_errors++; return -1;}
                if (ret == 0) {
                        uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
                        wsgi_req->write_errors++;
                        return -1;
                }
	}

	wsgi_req->response_size += wsgi_req->write_pos;
	// reset for the next write
        wsgi_req->write_pos = 0;

	// now we need to check if the chunk must be stored
	if (wsgi_req->cache_it) {
		if (!wsgi_req->cached_response) {
			wsgi_req->cached_response = uwsgi_buffer_new(len);
		}
		// if we are unable to append the buffer, we just stop caching it
		if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) {
			uwsgi_buffer_destroy(wsgi_req->cache_it);
			wsgi_req->cache_it = NULL;
		}
	}

	return UWSGI_OK;	
}
Beispiel #3
0
// this is the function called by all request plugins to send chunks to the client
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {

	if (wsgi_req->write_errors) return -1;

	// do not commit headers until a response_buffer is available
	if (!wsgi_req->response_buffer && !wsgi_req->headers_sent) {
		int ret = uwsgi_response_write_headers_do(wsgi_req);
                if (ret == UWSGI_OK) goto sendbody;
                if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
		wsgi_req->write_errors++;
                return -1;
	}

sendbody:

	if (len == 0) return UWSGI_OK;
	
	if (wsgi_req->response_buffer) {
		if (uwsgi_buffer_append(wsgi_req->response_buffer, buf, len)) {
			wsgi_req->write_errors++;
			return -1;
		}
		return UWSGI_OK;
	}

	for(;;) {
		int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
		if (ret < 0) {
			if (!uwsgi.ignore_write_errors) {
				uwsgi_error("uwsgi_response_write_body_do()");
			}
			wsgi_req->write_errors++;
			return -1;
		}
		if (ret == UWSGI_OK) {
			break;
		}
		ret = uwsgi_wait_write_req(wsgi_req);			
		if (ret < 0) { wsgi_req->write_errors++; return -1;}
                if (ret == 0) {
                        uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
                        wsgi_req->write_errors++;
                        return -1;
                }
	}

	wsgi_req->response_size += wsgi_req->write_pos;
	// reset for the next write
        wsgi_req->write_pos = 0;

	return UWSGI_OK;	
}
Beispiel #4
0
int uwsgi_response_sendfile_do(struct wsgi_request *wsgi_req, int fd, size_t pos, size_t len) {

	int can_close = 1;

	if (fd == wsgi_req->sendfile_fd) can_close = 0;

	if (wsgi_req->write_errors) return -1;

	if (!wsgi_req->headers_sent) {
		int ret = uwsgi_response_write_headers_do(wsgi_req);
		if (ret == UWSGI_OK) goto sendfile;
		if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
		wsgi_req->write_errors++;
		if (can_close) close(fd);
		return -1;
	}

sendfile:

	if (len == 0) {
		struct stat st;
		if (fstat(fd, &st)) {
			uwsgi_error("fstat()");
			wsgi_req->write_errors++;
			if (can_close) close(fd);
			return -1;
		}
		if (pos >= (size_t)st.st_size) return UWSGI_OK;
		len = st.st_size;
	}

	if (wsgi_req->socket->can_offload) {
		// of we cannot close the socket (before the app will close it later)
		// let's dup it
		if (!can_close) {
			int tmp_fd = dup(fd);
			if (tmp_fd < 0) {
				uwsgi_error("uwsgi_response_sendfile_do()/dup()");
				wsgi_req->write_errors++;
				return -1;
			}
			fd = tmp_fd;
			can_close = 1;
		}
       		if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, len)) {
                	wsgi_req->via = UWSGI_VIA_OFFLOAD;
			wsgi_req->response_size += len;
                        return 0;
                }
		wsgi_req->write_errors++;
		if (can_close) close(fd);
		return -1;
	}


        wsgi_req->via = UWSGI_VIA_SENDFILE;

        for(;;) {
                int ret = wsgi_req->socket->proto_sendfile(wsgi_req, fd, pos, len);
                if (ret < 0) {
                        if (!uwsgi.ignore_write_errors) {
                                uwsgi_error("uwsgi_response_sendfile_do()");
                        }
			wsgi_req->write_errors++;
			if (can_close) close(fd);
                        return -1;
                }
                if (ret == UWSGI_OK) {
                        break;
                }
                ret = uwsgi_wait_write_req(wsgi_req);
                if (ret < 0) {
			wsgi_req->write_errors++;
			if (can_close) close(fd);
			return -1;
		}
		if (ret == 0) {
                        uwsgi_log("uwsgi_response_sendfile_do() TIMEOUT !!!\n");
                        wsgi_req->write_errors++;
                        return -1;
                }	
        }

        wsgi_req->response_size += wsgi_req->write_pos;
	// reset for the next write
        wsgi_req->write_pos = 0;
	// close the file descriptor
	if (can_close) close(fd);
        return UWSGI_OK;
}
Beispiel #5
0
int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

        struct stat st;
        int ret = UWSGI_ROUTE_BREAK;

        struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

        int fd = open(ub->buf, O_RDONLY);
        if (fd < 0) {
                if (ur->custom)
                        ret = UWSGI_ROUTE_NEXT;
                goto end;
        }

        if (fstat(fd, &st)) {
                goto end2;
        }

        struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
        if (!ub_s) goto end2;

        // static file - don't update avg_rt after request
        wsgi_req->do_not_account_avg_rt = 1;

	if (urfc->no_headers) {
                uwsgi_buffer_destroy(ub_s);
		goto send;
	}

        if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
                uwsgi_buffer_destroy(ub_s);
                goto end2;
        }
        uwsgi_buffer_destroy(ub_s);
        if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
        if (urfc->mime) {
                size_t mime_type_len = 0;
                char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
                if (mime_type) {
                        if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
                }
                else {
                        if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
                }
        }
        else {
                if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
        }

send:

	if (!wsgi_req->headers_sent) {
                if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
        }

	if (wsgi_req->socket->can_offload) {
		if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, st.st_size)) {
                        wsgi_req->via = UWSGI_VIA_OFFLOAD;
                        wsgi_req->response_size += st.st_size;
                	// the fd will be closed by the offload engine
			goto end;
		}
	}

        if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) {
                wsgi_req->via = UWSGI_VIA_SENDFILE;
                wsgi_req->response_size += st.st_size;
        }

end2:
        close(fd);
end:
        uwsgi_buffer_destroy(ub);
        return ret;
}
Beispiel #6
0
// "next" || "continue" || "break(.*)" || "goon" || "goto .+"
static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
        int ret = -1;
        // this is the list of args
        char *argv[UMAX8];
        // this is the size of each argument
        uint16_t argvs[UMAX8];
        // this is a placeholder for tmp uwsgi_buffers
        struct uwsgi_buffer *ubs[UMAX8];

        char **r_argv = (char **) ur->data2;
        uint16_t *r_argvs = (uint16_t *) ur->data3;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        uint64_t i;
        for(i=0;i<ur->custom;i++) {
                ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
                if (!ubs[i]) goto end;
                argv[i] = ubs[i]->buf;
                argvs[i] = ubs[i]->pos;
        }

        // ok we now need to check it it is a local call or a remote one
        char *func = uwsgi_str(ur->data);
        char *remote = NULL;
        char *at = strchr(func, '@');
        if (at) {
                *at = 0;
                remote = at+1;
        }
        uint16_t size;
        char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
        free(func);
        if (!response) goto end;

        ret = UWSGI_ROUTE_CONTINUE;
	if (!uwsgi_strncmp(response, size, "next", 4 )) {
        	ret = UWSGI_ROUTE_NEXT;
	}
	else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
        	ret = UWSGI_ROUTE_CONTINUE;
	}
	else if (!uwsgi_starts_with(response, size, "break", 5 )) {
        	ret = UWSGI_ROUTE_BREAK;
		if (size > 6) {
			if (uwsgi_response_prepare_headers(wsgi_req, response+6, size-6)) goto end0;
                	if (uwsgi_response_add_connection_close(wsgi_req)) goto end0;
                	if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end0;
                	// no need to check for return value
                	uwsgi_response_write_headers_do(wsgi_req);
		}
	}
	else if (!uwsgi_starts_with(response, size, "goto ", 5)) {
		ret = UWSGI_ROUTE_BREAK;
		if (size > 5) {
		 	// find the label
        		struct uwsgi_route *routes = uwsgi.routes;
        		while(routes) {
                		if (!routes->label) goto next;
                		if (!uwsgi_strncmp(routes->label, routes->label_len, response+5, size-5)) {
					ret = UWSGI_ROUTE_NEXT;
                        		wsgi_req->route_goto = routes->pos;
                        		goto found;
                		}
next:
               			routes = routes->next;
        		}
			goto end0;	
found:
        		if (wsgi_req->route_goto <= wsgi_req->route_pc) {
                		wsgi_req->route_goto = 0;
                		uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
				ret = UWSGI_ROUTE_BREAK;
        		}
		}
	}

end0:
        free(response);

end:
        for(i=0;i<ur->custom;i++) {
                if (ubs[i] != NULL) {
                        uwsgi_buffer_destroy(ubs[i]);
                }
        }
        return ret;
}
Beispiel #7
0
static int uwsgi_ssh_request_file(
	struct wsgi_request *wsgi_req,
	char* filepath,
	struct uwsgi_ssh_mountpoint *usm
	) {

	int sock = -1;
	int return_status = 0;

	LIBSSH2_SESSION *session = NULL;
	if (uwsgi_init_ssh_session(usm, &sock, &session)) {
		uwsgi_log("[SSH] session initialization failed. Is the SSH server up?\n");
		return_status = 500;
		goto shutdown;
	}

	LIBSSH2_SFTP *sftp_session = NULL;
	do {
		sftp_session = libssh2_sftp_init(session);

		if (!sftp_session) {
			if ((libssh2_session_last_errno(session)) == LIBSSH2_ERROR_EAGAIN) {
				if (uwsgi_ssh_waitsocket(sock, session)) {
					return_status = 500;
					goto shutdown;
				}
			} else {
				uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_init()");
				return_status = 500;
				goto shutdown;
			}
		}
	} while (!sftp_session);

	// Request file stats via SFTP
	LIBSSH2_SFTP_ATTRIBUTES file_attrs;
	int rc;
	while ((rc = libssh2_sftp_stat(sftp_session, filepath, &file_attrs)) == LIBSSH2_ERROR_EAGAIN) {
		if (uwsgi_ssh_waitsocket(sock, session)) {
			return_status = 500;
			goto shutdown;
		}
	}

	if (rc < 0) {
		// If it fails, requested file could not exist.
		if (rc == LIBSSH2_ERROR_SFTP_PROTOCOL && libssh2_sftp_last_error(sftp_session) == LIBSSH2_FX_NO_SUCH_FILE) {
				return_status = 404;
		} else {
			uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_stat()");
			return_status = 500;
		}
		goto sftp_shutdown;
	}

	if (wsgi_req->if_modified_since_len) {
		time_t ims = uwsgi_parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
		if (file_attrs.mtime <= (unsigned long)ims) {
			if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16) || uwsgi_response_write_headers_do(wsgi_req)) {
				uwsgi_error("uwsgi_parse_http_date()/uwsgi_response_prepare_headers(do)()");
			}
			return_status = 500;
			goto sftp_shutdown;
		}
	}

	if (uwsgi_response_prepare_headers(wsgi_req, "200", 3)) {
		uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_prepare_headers()");
		return_status = 500;
		goto sftp_shutdown;
	}

	if (uwsgi_response_add_content_length(wsgi_req, file_attrs.filesize)) {
		uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_length()");
		return_status = 500;
		goto sftp_shutdown;
	}

	if (uwsgi_response_add_last_modified(wsgi_req, file_attrs.mtime)) {
		uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_last_modified()");
		return_status = 500;
		goto sftp_shutdown;
	}

	size_t mime_type_len = 0;
	char *mime_type = uwsgi_get_mime_type(filepath, strlen(filepath), &mime_type_len);
	if (mime_type) {
		if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) {
			uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_type()");
			// goto sftp_shutdown;
		}
	}

	// Request a file via SFTP
	LIBSSH2_SFTP_HANDLE *sftp_handle = NULL;
	do {
		sftp_handle = libssh2_sftp_open(sftp_session, filepath, LIBSSH2_FXF_READ, 0);

		if (!sftp_handle) {
			if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
				uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_open()");
				return_status = 500;
				goto sftp_shutdown;
			} else {
				if (uwsgi_ssh_waitsocket(sock, session)) {
					return_status = 500;
					goto sftp_shutdown;
				}
			}
		}
	} while (!sftp_handle);

	size_t buffer_size = uwsgi.page_size;
	void *buffer = alloca(buffer_size);
	libssh2_uint64_t read_size = 0;

	while (read_size < file_attrs.filesize) {
		rc = libssh2_sftp_read(sftp_handle, buffer, buffer_size);

		if (rc == LIBSSH2_ERROR_EAGAIN) {
			if (uwsgi_ssh_waitsocket(sock, session)) {
				return_status = 500;
				goto sftp_shutdown;
			}
		} else if (rc < 0) {
			uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_read()");
			break;
		} else {
			read_size += rc;
			if (uwsgi_response_write_body_do(wsgi_req, buffer, rc)) {
				uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_write_body_do()");
				break;
			}
		}
	}

	while ((rc = libssh2_sftp_close(sftp_handle)) == LIBSSH2_ERROR_EAGAIN) {
		if (uwsgi_ssh_waitsocket(sock, session)) {
			return_status = 500;
			goto sftp_shutdown;
		}
	};
	if (rc < 0) {
		uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_close()");
	}

sftp_shutdown:

	while ((rc = libssh2_sftp_shutdown(sftp_session)) == LIBSSH2_ERROR_EAGAIN) {
		uwsgi_ssh_waitsocket(sock, session);
	}
	if (rc < 0) {
		uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_shutdown()");
	}

shutdown:

	while (libssh2_session_disconnect(session, "Normal Shutdown, thank you!") == LIBSSH2_ERROR_EAGAIN) {
		uwsgi_ssh_waitsocket(sock, session);
	}
	libssh2_session_free(session);
	close(sock);
	libssh2_exit();
	return return_status;
}
Beispiel #8
0
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
	
	struct uwsgi_buffer *ub = NULL;

	// 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;

	struct uwsgi_buffer *ub_url = NULL;
	if (ur->data3_len) {
		ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len);
        	if (!ub_url) {
			uwsgi_buffer_destroy(ub_addr);
			return UWSGI_ROUTE_BREAK;
		}
	}

	// convert the wsgi_request to an http proxy request
	if (ur->custom & 0x02) {
		ub = uwsgi_buffer_new(uwsgi.page_size);
	}
	else if (ur->custom & 0x04) {
		ub = uwsgi_to_http_dumb(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
	}
	else {
		ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);	
	}

	if (!ub) {
		if (ub_url) uwsgi_buffer_destroy(ub_url);
		uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
		uwsgi_buffer_destroy(ub_addr);
                return UWSGI_ROUTE_NEXT;
	}

	if (ub_url) uwsgi_buffer_destroy(ub_url);

	// amount of body to send
	size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains;
	// append remaining body...
	if (wsgi_req->proto_parser_remains > 0) {
		if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
			uwsgi_buffer_destroy(ub);
			uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
			uwsgi_buffer_destroy(ub_addr);
               		return UWSGI_ROUTE_NEXT;
		}
		wsgi_req->post_pos += wsgi_req->proto_parser_remains;
		wsgi_req->proto_parser_remains = 0;
	}

	// ok now if have offload threads, directly use them
	if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
		// append buffered body
		if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
			if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
				uwsgi_buffer_destroy(ub);
				uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
				uwsgi_buffer_destroy(ub_addr);
               			return UWSGI_ROUTE_NEXT;
			}
		}

		// if we have a CONNECT request, let's confirm it to the client
		if (ur->custom & 0x02) {
			if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
                        // no need to check for return value
                        uwsgi_response_write_headers_do(wsgi_req);	
		}

        	if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
                	wsgi_req->via = UWSGI_VIA_OFFLOAD;
			wsgi_req->status = 202;
			uwsgi_buffer_destroy(ub_addr);
			return UWSGI_ROUTE_BREAK;
                }
	}

	if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) {
		uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
	}

end:
	uwsgi_buffer_destroy(ub);
	uwsgi_buffer_destroy(ub_addr);

	return UWSGI_ROUTE_BREAK;

}
Beispiel #9
0
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {

	size_t mime_type_size = 0;
	char http_last_modified[49];

	if (uwsgi.threads > 1)
		pthread_mutex_lock(&uwsgi.lock_static);

	char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);

	if (uwsgi.threads > 1)
		pthread_mutex_unlock(&uwsgi.lock_static);

	if (wsgi_req->if_modified_since_len) {
		time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
		if (st->st_mtime <= ims) {
			uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16); 
			return uwsgi_response_write_headers_do(wsgi_req);
		}
	}
#ifdef UWSGI_DEBUG
	uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif

	size_t fsize = st->st_size;
        if (wsgi_req->range_to) {
        	fsize = wsgi_req->range_to - wsgi_req->range_from;
                if (fsize > (size_t)st->st_size) {
                	fsize = st->st_size;
                }
        }
	else {
        	// reset in case of inconsistent size
        	if (wsgi_req->range_from > fsize) {
        		wsgi_req->range_from = 0;
                	fsize = 0 ;
        	}
		else {
			fsize -= wsgi_req->range_from;
		}
	}

	// HTTP status
	if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
		if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
	}
	else {
		if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
	}

#ifdef UWSGI_PCRE
	uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
	uwsgi_add_expires_path_info(wsgi_req, st);
	uwsgi_add_expires_uri(wsgi_req, st);
#endif

	// Content-Type (if available)
	if (mime_type_size > 0 && mime_type) {
		if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
		// check for content-type related headers
		uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
	}

	// increase static requests counter
	uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;

	// nginx
	if (uwsgi.file_serve_mode == 1) {
		if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
		// this is the final header (\r\n added)
		int size = set_http_date(st->st_mtime, http_last_modified);
		if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
	}
	// apache
	else if (uwsgi.file_serve_mode == 2) {
		if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
		// this is the final header (\r\n added)
		int size = set_http_date(st->st_mtime, http_last_modified);
		if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
	}
	// raw
	else {
		// here we need to choose if we want the gzip variant;
		if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
			if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
		}
		// set Content-Length (to fsize NOT st->st_size)
		if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
		if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
			// here use teh original size !!!
			if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
		}
		int size = set_http_date(st->st_mtime, http_last_modified);
		if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;

		// if it is a HEAD request just skip transfer
		if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
			wsgi_req->status = 200;
			return 0;
		}

		// Ok, the file must be transferred from uWSGI
		// offloading will be automatically managed
		int fd = open(real_filename, O_RDONLY);
		if (fd < 0) return -1;
		// fd will be closed in the following function
		uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize);
	}

	wsgi_req->status = 200;
	return 0;
}
Beispiel #10
0
// this is the function called by all request plugins to send chunks to the client
int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) {

	if (wsgi_req->write_errors) return -1;
	if (wsgi_req->ignore_body) return UWSGI_OK;

	// if the transformation chain returns 1, we are in buffering mode
	if (wsgi_req->transformed_chunk_len == 0 && wsgi_req->transformations) {
		int t_ret = uwsgi_apply_transformations(wsgi_req, buf, len);
		if (t_ret == 0) {
			buf = wsgi_req->transformed_chunk;
			len = wsgi_req->transformed_chunk_len;
			// reset transformation
			wsgi_req->transformed_chunk = NULL;
			wsgi_req->transformed_chunk_len = 0;
			goto write;
		}
		if (t_ret == 1) {
			return UWSGI_OK;
		}
		wsgi_req->write_errors++;
		return -1;
	}

write:
	// send headers if not already sent
	if (!wsgi_req->headers_sent) {
		int ret = uwsgi_response_write_headers_do(wsgi_req);
                if (ret == UWSGI_OK) goto sendbody;
                if (ret == UWSGI_AGAIN) return UWSGI_AGAIN;
		wsgi_req->write_errors++;
                return -1;
	}

sendbody:

	if (len == 0) return UWSGI_OK;
	
	for(;;) {
		int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len);
		if (ret < 0) {
			if (!uwsgi.ignore_write_errors) {
				uwsgi_error("uwsgi_response_write_body_do()");
			}
			wsgi_req->write_errors++;
			return -1;
		}
		if (ret == UWSGI_OK) {
			break;
		}
		ret = uwsgi_wait_write_req(wsgi_req);			
		if (ret < 0) { wsgi_req->write_errors++; return -1;}
                if (ret == 0) {
                        uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n");
                        wsgi_req->write_errors++;
                        return -1;
                }
	}

	wsgi_req->response_size += wsgi_req->write_pos;
	// reset for the next write
        wsgi_req->write_pos = 0;

	return UWSGI_OK;	
}