📄 http.c
字号:
/* Unix SMB/CIFS implementation. http handling code Copyright (C) Andrew Tridgell 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "smbd/service_task.h"#include "web_server/web_server.h"#include "smbd/service_stream.h"#include "smbd/service.h"#include "lib/events/events.h"#include "system/time.h"#include "system/wait.h"#include "lib/appweb/esp/esp.h"#include "lib/appweb/ejs/ejsInternal.h"#include "lib/util/dlinklist.h"#include "lib/tls/tls.h"#include "scripting/ejs/smbcalls.h"#include "param/param.h"#define SAMBA_SESSION_KEY "SambaSessionId"#define HTTP_PREAUTH_URI "/scripting/preauth.esp"/* state of the esp subsystem for a specific request */struct esp_state { struct websrv_context *web; struct EspRequest *req; struct MprVar variables[ESP_OBJ_MAX]; struct session_data *session;};/* output the http headers*/static void http_output_headers(struct websrv_context *web){ int i; char *s; DATA_BLOB b; uint32_t content_length = 0; const char *response_string = "Unknown Code"; const struct { unsigned code; const char *response_string; } codes[] = { { 200, "OK" }, { 301, "Moved" }, { 302, "Found" }, { 303, "Method" }, { 304, "Not Modified" }, { 400, "Bad request" }, { 401, "Unauthorized" }, { 403, "Forbidden" }, { 404, "Not Found" }, { 500, "Internal Server Error" }, { 501, "Not implemented" } }; for (i=0;i<ARRAY_SIZE(codes);i++) { if (codes[i].code == web->output.response_code) { response_string = codes[i].response_string; } } if (web->output.headers == NULL) return; s = talloc_asprintf(web, "HTTP/1.0 %u %s\r\n", web->output.response_code, response_string); if (s == NULL) return; for (i=0;web->output.headers[i];i++) { s = talloc_asprintf_append_buffer(s, "%s\r\n", web->output.headers[i]); } /* work out the content length */ content_length = web->output.content.length; if (web->output.fd != -1) { struct stat st; fstat(web->output.fd, &st); content_length += st.st_size; } s = talloc_asprintf_append_buffer(s, "Content-Length: %u\r\n\r\n", content_length); if (s == NULL) return; b = web->output.content; web->output.content = data_blob_string_const(s); data_blob_append(web, &web->output.content, b.data, b.length); data_blob_free(&b);}/* return the local path for a URL*/static const char *http_local_path(struct websrv_context *web, const char *url, const char *base_dir){ int i; char *path; /* check that the url is OK */ if (url[0] != '/') return NULL; for (i=0;url[i];i++) { if ((!isalnum((unsigned char)url[i]) && !strchr("./_-", url[i])) || (url[i] == '.' && strchr("/.", url[i+1]))) { return NULL; } } path = talloc_asprintf(web, "%s/%s", base_dir, url+1); if (path == NULL) return NULL; if (directory_exist(path)) { path = talloc_asprintf_append_buffer(path, "/index.esp"); } return path;}/* called when esp wants to read a file to support include() calls*/static int http_readFile(EspHandle handle, char **buf, int *len, const char *path, const char *base_dir){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); int fd = -1; struct stat st; *buf = NULL; path = http_local_path(web, path, base_dir); if (path == NULL) goto failed; fd = open(path, O_RDONLY); if (fd == -1 || fstat(fd, &st) != 0 || !S_ISREG(st.st_mode)) goto failed; *buf = talloc_array(handle, char, st.st_size+1); if (*buf == NULL) goto failed; if (read(fd, *buf, st.st_size) != st.st_size) goto failed; (*buf)[st.st_size] = 0; close(fd); *len = st.st_size; return 0;failed: DEBUG(0,("Failed to read file %s - %s\n", path, strerror(errno))); if (fd != -1) close(fd); talloc_free(*buf); *buf = NULL; return -1;}static int http_readFileFromSwatDir(EspHandle handle, char **buf, int *len, const char *path){ return http_readFile(handle, buf, len, path, lp_swat_directory(global_loadparm));}/* called when esp wants to find the real path of a file*/static int http_mapToStorage(EspHandle handle, char *path, int len, const char *uri, int flags){ if (uri == NULL || strlen(uri) >= len) return -1; strncpy(path, uri, len); return 0;}/* called when esp wants to output something*/static int http_writeBlock(EspHandle handle, const char *buf, int size){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); if (!data_blob_append(web, &web->output.content, buf, size)) return -1; return size;}/* set a http header*/static void http_setHeader(EspHandle handle, const char *value, bool allowMultiple){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); char *p = strchr(value, ':'); if (p && !allowMultiple && web->output.headers) { int i; for (i=0;web->output.headers[i];i++) { if (strncmp(web->output.headers[i], value, (p+1)-value) == 0) { web->output.headers[i] = talloc_strdup(web, value); return; } } } web->output.headers = str_list_add(web->output.headers, value); talloc_steal(web, web->output.headers);}/* set a http response code*/static void http_setResponseCode(EspHandle handle, int code){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); web->output.response_code = code;}/* redirect to another web page */static void http_redirect(EspHandle handle, int code, char *url){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); const char *host = web->input.host; /* form the full url, unless it already looks like a url */ if (strchr(url, ':') == NULL) { if (host == NULL) { struct socket_address *socket_address = socket_get_my_addr(web->conn->socket, web); if (socket_address == NULL) goto internal_error; host = talloc_asprintf(web, "%s:%u", socket_address->addr, socket_address->port); } if (host == NULL) goto internal_error; if (url[0] != '/') { char *p = strrchr(web->input.url, '/'); if (p == web->input.url) { url = talloc_asprintf(web, "http%s://%s/%s", tls_enabled(web->conn->socket)?"s":"", host, url); } else { int dirlen = p - web->input.url; url = talloc_asprintf(web, "http%s://%s%*.*s/%s", tls_enabled(web->conn->socket)?"s":"", host, dirlen, dirlen, web->input.url, url); } if (url == NULL) goto internal_error; } } http_setHeader(handle, talloc_asprintf(web, "Location: %s", url), 0); /* make sure we give a valid redirect code */ if (code >= 300 && code < 400) { http_setResponseCode(handle, code); } else { http_setResponseCode(handle, 302); } return;internal_error: http_error(web, 500, "Internal server error");}/* setup a cookie*/static void http_setCookie(EspHandle handle, const char *name, const char *value, int lifetime, const char *path, bool secure){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); char *buf; if (lifetime > 0) { buf = talloc_asprintf(web, "Set-Cookie: %s=%s; path=%s; Expires=%s; %s", name, value, path?path:"/", http_timestring(web, time(NULL)+lifetime), secure?"secure":""); } else { buf = talloc_asprintf(web, "Set-Cookie: %s=%s; path=%s; %s", name, value, path?path:"/", secure?"secure":""); } http_setHeader(handle, "Cache-control: no-cache=\"set-cookie\"", 0); http_setHeader(handle, buf, 0); talloc_free(buf);}/* return the session id*/static const char *http_getSessionId(EspHandle handle){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); return web->session->id;}/* setup a session*/static void http_createSession(EspHandle handle, int timeout){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); if (web->session) { web->session->lifetime = timeout; http_setCookie(web, SAMBA_SESSION_KEY, web->session->id, web->session->lifetime, "/", 0); }}/* destroy a session*/static void http_destroySession(EspHandle handle){ struct websrv_context *web = talloc_get_type(handle, struct websrv_context); talloc_free(web->session); web->session = NULL;}/* setup for a raw http level error*/void http_error(struct websrv_context *web, int code, const char *info){ char *s; s = talloc_asprintf(web,"<HTML><HEAD><TITLE>Error %u</TITLE></HEAD><BODY><H1>Error %u</H1><pre>%s</pre><p></BODY></HTML>\r\n\r\n", code, code, info); if (s == NULL) { stream_terminate_connection(web->conn, "http_error: out of memory"); return; } http_writeBlock(web, s, strlen(s)); http_setResponseCode(web, code); http_output_headers(web); EVENT_FD_NOT_READABLE(web->conn->event.fde); EVENT_FD_WRITEABLE(web->conn->event.fde); web->output.output_pending = true;}/* map a unix error code to a http error*/void http_error_unix(struct websrv_context *web, const char *info){ int code = 500; switch (errno) { case ENOENT: case EISDIR: code = 404; break; case EACCES: code = 403; break; } info = talloc_asprintf(web, "%s<p>%s<p>\n", info, strerror(errno)); http_error(web, code, info);}/* a simple file request*/static void http_simple_request(struct websrv_context *web){ const char *url = web->input.url; const char *path; struct stat st; path = http_local_path(web, url, lp_swat_directory(web->task->lp_ctx)); if (path == NULL) goto invalid; /* looks ok */ web->output.fd = open(path, O_RDONLY); if (web->output.fd == -1) { DEBUG(0,("Failed to read file %s - %s\n", path, strerror(errno))); http_error_unix(web, path); return; } if (fstat(web->output.fd, &st) != 0 || !S_ISREG(st.st_mode)) { close(web->output.fd); goto invalid; } return;invalid: http_error(web, 400, "Malformed URL");}/* setup the standard ESP arrays*/static void http_setup_arrays(struct esp_state *esp){ struct websrv_context *web = esp->web; struct esp_data *edata = talloc_get_type(web->task->private, struct esp_data); struct EspRequest *req = esp->req; struct socket_address *socket_address = socket_get_my_addr(web->conn->socket, esp); struct socket_address *peer_address = socket_get_peer_addr(web->conn->socket, esp); char *p;#define SETVAR(type, name, value) do { \ const char *v = value; \ if (v) espSetStringVar(req, type, name, v); \} while (0) SETVAR(ESP_REQUEST_OBJ, "CONTENT_LENGTH", talloc_asprintf(esp, "%u", web->input.content_length)); SETVAR(ESP_REQUEST_OBJ, "QUERY_STRING", web->input.query_string); SETVAR(ESP_REQUEST_OBJ, "POST_DATA", talloc_strndup(esp, web->input.partial.data, web->input.partial.length)); SETVAR(ESP_REQUEST_OBJ, "REQUEST_METHOD", web->input.post_request?"POST":"GET"); SETVAR(ESP_REQUEST_OBJ, "REQUEST_URI", web->input.url); p = strrchr(web->input.url, '/'); SETVAR(ESP_REQUEST_OBJ, "SCRIPT_NAME", p+1); SETVAR(ESP_REQUEST_OBJ, "SCRIPT_FILENAME", web->input.url); if (peer_address) { struct MprVar mpv = mprObject("socket_address"); mprSetPtrChild(&mpv, "socket_address", peer_address); espSetVar(req, ESP_REQUEST_OBJ, "REMOTE_SOCKET_ADDRESS", mpv); SETVAR(ESP_REQUEST_OBJ, "REMOTE_ADDR", peer_address->addr); } p = socket_get_peer_name(web->conn->socket, esp); SETVAR(ESP_REQUEST_OBJ, "REMOTE_HOST", p); SETVAR(ESP_REQUEST_OBJ, "REMOTE_USER", ""); SETVAR(ESP_REQUEST_OBJ, "CONTENT_TYPE", web->input.content_type); if (web->session) { SETVAR(ESP_REQUEST_OBJ, "SESSION_ID", web->session->id); } SETVAR(ESP_REQUEST_OBJ, "COOKIE_SUPPORT", web->input.cookie?"true":"false"); SETVAR(ESP_HEADERS_OBJ, "HTTP_REFERER", web->input.referer); SETVAR(ESP_HEADERS_OBJ, "HOST", web->input.host); SETVAR(ESP_HEADERS_OBJ, "ACCEPT_ENCODING", web->input.accept_encoding); SETVAR(ESP_HEADERS_OBJ, "ACCEPT_LANGUAGE", web->input.accept_language); SETVAR(ESP_HEADERS_OBJ, "ACCEPT_CHARSET", web->input.accept_charset); SETVAR(ESP_HEADERS_OBJ, "COOKIE", web->input.cookie); SETVAR(ESP_HEADERS_OBJ, "USER_AGENT", web->input.user_agent); if (socket_address) { SETVAR(ESP_SERVER_OBJ, "SERVER_ADDR", socket_address->addr); SETVAR(ESP_SERVER_OBJ, "SERVER_NAME", socket_address->addr); SETVAR(ESP_SERVER_OBJ, "SERVER_HOST", socket_address->addr); SETVAR(ESP_SERVER_OBJ, "SERVER_PORT", talloc_asprintf(esp, "%u", socket_address->port)); } SETVAR(ESP_SERVER_OBJ, "DOCUMENT_ROOT", lp_swat_directory(esp->web->task->lp_ctx)); SETVAR(ESP_SERVER_OBJ, "SERVER_PROTOCOL", tls_enabled(web->conn->socket)?"https":"http"); SETVAR(ESP_SERVER_OBJ, "SERVER_SOFTWARE", "SAMBA"); SETVAR(ESP_SERVER_OBJ, "GATEWAY_INTERFACE", "CGI/1.1"); SETVAR(ESP_SERVER_OBJ, "TLS_SUPPORT", tls_support(edata->tls_params)?"true":"false");}#if HAVE_SETJMP_H/* the esp scripting lirary generates exceptions when it hits a major error. We need to catch these and report a internal server error via http*/static jmp_buf ejs_exception_buf;static const char *exception_reason;static void web_server_ejs_exception(const char *reason){ Ejs *ep = ejsPtr(0); if (ep) { ejsSetErrorMsg(0, "%s", reason); exception_reason = ep->error; } else { exception_reason = reason; } DEBUG(0,("%s", exception_reason)); longjmp(ejs_exception_buf, -1);}#elsestatic void web_server_ejs_exception(const char *reason){ DEBUG(0,("%s", reason)); smb_panic(reason);}#endif/* process a esp request*/static void esp_request(struct esp_state *esp, const char *url){ struct websrv_context *web = esp->web; int size; int res; char *emsg = NULL, *buf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -