2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "smbd/service_task.h"
25 #include "web_server/web_server.h"
26 #include "smbd/service_stream.h"
27 #include "smbd/service.h"
28 #include "lib/events/events.h"
29 #include "system/time.h"
30 #include "lib/appweb/esp/esp.h"
31 #include "lib/appweb/ejs/ejsInternal.h"
32 #include "lib/util/dlinklist.h"
33 #include "lib/tls/tls.h"
34 #include "scripting/ejs/smbcalls.h"
36 #define SWAT_SESSION_KEY "SwatSessionId"
37 #define HTTP_PREAUTH_URI "/scripting/preauth.esp"
38 #define JSONRPC_REQUEST "/services"
39 #define JSONRPC_SERVER "/services/request.esp"
41 /* state of the esp subsystem for a specific request */
43 struct websrv_context *web;
44 struct EspRequest *req;
45 struct MprVar variables[ESP_OBJ_MAX];
46 struct session_data *session;
50 output the http headers
52 static void http_output_headers(struct websrv_context *web)
57 uint32_t content_length = 0;
58 const char *response_string = "Unknown Code";
61 const char *response_string;
67 { 304, "Not Modified" },
68 { 400, "Bad request" },
69 { 401, "Unauthorized" },
72 { 500, "Internal Server Error" },
73 { 501, "Not implemented" }
75 for (i=0;i<ARRAY_SIZE(codes);i++) {
76 if (codes[i].code == web->output.response_code) {
77 response_string = codes[i].response_string;
81 if (web->output.headers == NULL) return;
82 s = talloc_asprintf(web, "HTTP/1.0 %u %s\r\n",
83 web->output.response_code, response_string);
84 if (s == NULL) return;
85 for (i=0;web->output.headers[i];i++) {
86 s = talloc_asprintf_append(s, "%s\r\n", web->output.headers[i]);
89 /* work out the content length */
90 content_length = web->output.content.length;
91 if (web->output.fd != -1) {
93 fstat(web->output.fd, &st);
94 content_length += st.st_size;
96 s = talloc_asprintf_append(s, "Content-Length: %u\r\n\r\n", content_length);
97 if (s == NULL) return;
99 b = web->output.content;
100 web->output.content = data_blob_string_const(s);
101 data_blob_append(web, &web->output.content, b.data, b.length);
106 return the local path for a URL
108 static const char *http_local_path(struct websrv_context *web, const char *url)
113 /* check that the url is OK */
114 if (url[0] != '/') return NULL;
116 for (i=0;url[i];i++) {
117 if ((!isalnum((unsigned char)url[i]) && !strchr("./_-", url[i])) ||
118 (url[i] == '.' && strchr("/.", url[i+1]))) {
123 path = talloc_asprintf(web, "%s/%s", lp_swat_directory(), url+1);
124 if (path == NULL) return NULL;
126 if (directory_exist(path)) {
127 path = talloc_asprintf_append(path, "/index.esp");
133 called when esp wants to read a file to support include() calls
135 static int http_readFile(EspHandle handle, char **buf, int *len, const char *path)
137 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
142 path = http_local_path(web, path);
143 if (path == NULL) goto failed;
145 fd = open(path, O_RDONLY);
146 if (fd == -1 || fstat(fd, &st) != 0 || !S_ISREG(st.st_mode)) goto failed;
148 *buf = talloc_size(handle, st.st_size+1);
149 if (*buf == NULL) goto failed;
151 if (read(fd, *buf, st.st_size) != st.st_size) goto failed;
153 (*buf)[st.st_size] = 0;
160 DEBUG(0,("Failed to read file %s - %s\n", path, strerror(errno)));
161 if (fd != -1) close(fd);
168 called when esp wants to find the real path of a file
170 static int http_mapToStorage(EspHandle handle, char *path, int len, const char *uri, int flags)
172 if (uri == NULL || strlen(uri) >= len) return -1;
173 strncpy(path, uri, len);
178 called when esp wants to output something
180 static int http_writeBlock(EspHandle handle, const char *buf, int size)
182 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
184 status = data_blob_append(web, &web->output.content, buf, size);
185 if (!NT_STATUS_IS_OK(status)) return -1;
193 static void http_setHeader(EspHandle handle, const char *value, bool allowMultiple)
195 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
196 char *p = strchr(value, ':');
198 if (p && !allowMultiple && web->output.headers) {
200 for (i=0;web->output.headers[i];i++) {
201 if (strncmp(web->output.headers[i], value, (p+1)-value) == 0) {
202 web->output.headers[i] = talloc_strdup(web, value);
208 web->output.headers = str_list_add(web->output.headers, value);
209 talloc_steal(web, web->output.headers);
213 set a http response code
215 static void http_setResponseCode(EspHandle handle, int code)
217 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
218 web->output.response_code = code;
222 redirect to another web page
224 static void http_redirect(EspHandle handle, int code, char *url)
226 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
227 const char *host = web->input.host;
229 /* form the full url, unless it already looks like a url */
230 if (strchr(url, ':') == NULL) {
232 struct socket_address *socket_address = socket_get_my_addr(web->conn->socket, web);
233 if (socket_address == NULL) goto internal_error;
234 host = talloc_asprintf(web, "%s:%u",
235 socket_address->addr, socket_address->port);
237 if (host == NULL) goto internal_error;
239 char *p = strrchr(web->input.url, '/');
240 if (p == web->input.url) {
241 url = talloc_asprintf(web, "http%s://%s/%s",
242 tls_enabled(web->conn->socket)?"s":"",
245 int dirlen = p - web->input.url;
246 url = talloc_asprintf(web, "http%s://%s%*.*s/%s",
247 tls_enabled(web->conn->socket)?"s":"",
249 dirlen, dirlen, web->input.url,
252 if (url == NULL) goto internal_error;
256 http_setHeader(handle, talloc_asprintf(web, "Location: %s", url), 0);
258 /* make sure we give a valid redirect code */
259 if (code >= 300 && code < 400) {
260 http_setResponseCode(handle, code);
262 http_setResponseCode(handle, 302);
267 http_error(web, 500, "Internal server error");
274 static void http_setCookie(EspHandle handle, const char *name, const char *value,
275 int lifetime, const char *path, bool secure)
277 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
281 buf = talloc_asprintf(web, "Set-Cookie: %s=%s; path=%s; Expires=%s; %s",
282 name, value, path?path:"/",
283 http_timestring(web, time(NULL)+lifetime),
286 buf = talloc_asprintf(web, "Set-Cookie: %s=%s; path=%s; %s",
287 name, value, path?path:"/",
290 http_setHeader(handle, "Cache-control: no-cache=\"set-cookie\"", 0);
291 http_setHeader(handle, buf, 0);
296 return the session id
298 static const char *http_getSessionId(EspHandle handle)
300 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
301 return web->session->id;
307 static void http_createSession(EspHandle handle, int timeout)
309 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
311 web->session->lifetime = timeout;
312 http_setCookie(web, SWAT_SESSION_KEY, web->session->id,
313 web->session->lifetime, "/", 0);
320 static void http_destroySession(EspHandle handle)
322 struct websrv_context *web = talloc_get_type(handle, struct websrv_context);
323 talloc_free(web->session);
329 setup for a raw http level error
331 void http_error(struct websrv_context *web, int code, const char *info)
334 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",
337 stream_terminate_connection(web->conn, "http_error: out of memory");
340 http_writeBlock(web, s, strlen(s));
341 http_setResponseCode(web, code);
342 http_output_headers(web);
343 EVENT_FD_NOT_READABLE(web->conn->event.fde);
344 EVENT_FD_WRITEABLE(web->conn->event.fde);
345 web->output.output_pending = True;
349 map a unix error code to a http error
351 void http_error_unix(struct websrv_context *web, const char *info)
363 info = talloc_asprintf(web, "%s<p>%s<p>\n", info, strerror(errno));
364 http_error(web, code, info);
369 a simple file request
371 static void http_simple_request(struct websrv_context *web)
373 const char *url = web->input.url;
377 path = http_local_path(web, url);
378 if (path == NULL) goto invalid;
381 web->output.fd = open(path, O_RDONLY);
382 if (web->output.fd == -1) {
383 DEBUG(0,("Failed to read file %s - %s\n", path, strerror(errno)));
384 http_error_unix(web, path);
388 if (fstat(web->output.fd, &st) != 0 || !S_ISREG(st.st_mode)) {
389 close(web->output.fd);
396 http_error(web, 400, "Malformed URL");
400 setup the standard ESP arrays
402 static void http_setup_arrays(struct esp_state *esp)
404 struct websrv_context *web = esp->web;
405 struct esp_data *edata = talloc_get_type(web->task->private, struct esp_data);
406 struct EspRequest *req = esp->req;
407 struct socket_address *socket_address = socket_get_my_addr(web->conn->socket, esp);
408 struct socket_address *peer_address = socket_get_peer_addr(web->conn->socket, esp);
411 #define SETVAR(type, name, value) do { \
412 const char *v = value; \
413 if (v) espSetStringVar(req, type, name, v); \
416 SETVAR(ESP_REQUEST_OBJ, "CONTENT_LENGTH",
417 talloc_asprintf(esp, "%u", web->input.content_length));
418 SETVAR(ESP_REQUEST_OBJ, "QUERY_STRING", web->input.query_string);
419 SETVAR(ESP_REQUEST_OBJ, "POST_DATA",
421 web->input.partial.data,
422 web->input.partial.length));
423 SETVAR(ESP_REQUEST_OBJ, "REQUEST_METHOD", web->input.post_request?"POST":"GET");
424 SETVAR(ESP_REQUEST_OBJ, "REQUEST_URI", web->input.url);
425 p = strrchr(web->input.url, '/');
426 SETVAR(ESP_REQUEST_OBJ, "SCRIPT_NAME", p+1);
427 SETVAR(ESP_REQUEST_OBJ, "SCRIPT_FILENAME", web->input.url);
429 struct MprVar mpv = mprObject("socket_address");
430 mprSetPtrChild(&mpv, "socket_address", peer_address);
431 espSetVar(req, ESP_REQUEST_OBJ, "REMOTE_SOCKET_ADDRESS", mpv);
432 SETVAR(ESP_REQUEST_OBJ, "REMOTE_ADDR", peer_address->addr);
434 p = socket_get_peer_name(web->conn->socket, esp);
435 SETVAR(ESP_REQUEST_OBJ, "REMOTE_HOST", p);
436 SETVAR(ESP_REQUEST_OBJ, "REMOTE_USER", "");
437 SETVAR(ESP_REQUEST_OBJ, "CONTENT_TYPE", web->input.content_type);
439 SETVAR(ESP_REQUEST_OBJ, "SESSION_ID", web->session->id);
441 SETVAR(ESP_REQUEST_OBJ, "COOKIE_SUPPORT", web->input.cookie?"True":"False");
443 SETVAR(ESP_HEADERS_OBJ, "HTT_REFERER", web->input.referer);
444 SETVAR(ESP_HEADERS_OBJ, "HOST", web->input.host);
445 SETVAR(ESP_HEADERS_OBJ, "ACCEPT_ENCODING", web->input.accept_encoding);
446 SETVAR(ESP_HEADERS_OBJ, "ACCEPT_LANGUAGE", web->input.accept_language);
447 SETVAR(ESP_HEADERS_OBJ, "ACCEPT_CHARSET", web->input.accept_charset);
448 SETVAR(ESP_HEADERS_OBJ, "COOKIE", web->input.cookie);
449 SETVAR(ESP_HEADERS_OBJ, "USER_AGENT", web->input.user_agent);
451 if (socket_address) {
452 SETVAR(ESP_SERVER_OBJ, "SERVER_ADDR", socket_address->addr);
453 SETVAR(ESP_SERVER_OBJ, "SERVER_NAME", socket_address->addr);
454 SETVAR(ESP_SERVER_OBJ, "SERVER_HOST", socket_address->addr);
455 SETVAR(ESP_SERVER_OBJ, "SERVER_PORT",
456 talloc_asprintf(esp, "%u", socket_address->port));
459 SETVAR(ESP_SERVER_OBJ, "DOCUMENT_ROOT", lp_swat_directory());
460 SETVAR(ESP_SERVER_OBJ, "SERVER_PROTOCOL", tls_enabled(web->conn->socket)?"https":"http");
461 SETVAR(ESP_SERVER_OBJ, "SERVER_SOFTWARE", "SWAT");
462 SETVAR(ESP_SERVER_OBJ, "GATEWAY_INTERFACE", "CGI/1.1");
463 SETVAR(ESP_SERVER_OBJ, "TLS_SUPPORT", tls_support(edata->tls_params)?"True":"False");
467 /* the esp scripting lirary generates exceptions when
468 it hits a major error. We need to catch these and
469 report a internal server error via http
472 static jmp_buf ejs_exception_buf;
473 static const char *exception_reason;
475 static void web_server_ejs_exception(const char *reason)
479 ejsSetErrorMsg(0, "%s", reason);
480 exception_reason = ep->error;
482 exception_reason = reason;
484 DEBUG(0,("%s", exception_reason));
485 longjmp(ejs_exception_buf, -1);
488 static void web_server_ejs_exception(const char *reason)
490 DEBUG(0,("%s", reason));
496 process a esp request
498 static void esp_request(struct esp_state *esp, const char *url)
500 struct websrv_context *web = esp->web;
503 char *emsg = NULL, *buf;
505 if (http_readFile(web, &buf, &size, url) != 0) {
506 http_error_unix(web, url);
511 if (setjmp(ejs_exception_buf) != 0) {
512 http_error(web, 500, exception_reason);
517 res = espProcessRequest(esp->req, url, buf, &emsg);
518 if (res != 0 && emsg) {
519 http_writeBlock(web, "<pre>", 5);
520 http_writeBlock(web, emsg, strlen(emsg));
521 http_writeBlock(web, "</pre>", 6);
527 process a JSON RPC request
529 static void jsonrpc_request(struct esp_state *esp)
531 const char *path = http_local_path(esp->web, JSONRPC_SERVER);
533 /* Ensure we got a valid path. */
535 /* should never occur */
536 http_error(esp->web, 500, "Internal server error");
540 /* Ensure that the JSON-RPC server request script exists */
541 if (!file_exist(path)) {
542 http_error_unix(esp->web, path);
546 /* Call the server request script */
547 esp_request(esp, JSONRPC_SERVER);
551 perform pre-authentication on every page if /scripting/preauth.esp
552 exists. If this script generates any non-whitepace output at all,
553 then we don't run the requested URL.
555 note that the preauth is run even for static pages such as images, but not
556 for JSON-RPC service requests which do their own authentication via the
559 static BOOL http_preauth(struct esp_state *esp)
561 const char *path = http_local_path(esp->web, HTTP_PREAUTH_URI);
564 http_error(esp->web, 500, "Internal server error");
567 if (!file_exist(path)) {
568 /* if the preath script is not installed then allow access */
571 esp_request(esp, HTTP_PREAUTH_URI);
572 for (i=0;i<esp->web->output.content.length;i++) {
573 if (!isspace(esp->web->output.content.data[i])) {
574 /* if the preauth has generated content, then force it
575 to be html, so that we can show the login page for
576 failed access to images */
577 http_setHeader(esp->web, "Content-Type: text/html", 0);
581 data_blob_free(&esp->web->output.content);
587 handling of + and % escapes in http variables
589 static const char *http_unescape(TALLOC_CTX *mem_ctx, const char *p)
591 char *s0 = talloc_strdup(mem_ctx, p);
593 if (s == NULL) return NULL;
597 if (*s == '+') *s = ' ';
598 if (*s == '%' && sscanf(s+1, "%02x", &v) == 1) {
600 memmove(s+1, s+3, strlen(s+3)+1);
609 set a form or GET variable
611 static void esp_putvar(struct esp_state *esp, const char *var, const char *value)
613 if (strcasecmp(var, SWAT_SESSION_KEY) == 0) {
614 /* special case support for browsers without cookie
616 esp->web->input.session_key = talloc_strdup(esp, value);
618 mprSetPropertyValue(&esp->variables[ESP_FORM_OBJ],
619 http_unescape(esp, var),
620 mprCreateStringVar(http_unescape(esp, value), 0));
626 parse the variables in a POST style request
628 static NTSTATUS http_parse_post(struct esp_state *esp)
630 DATA_BLOB b = esp->web->input.partial;
636 p = memchr(b.data, '&', b.length);
640 len = p - (char *)b.data;
642 line = talloc_strndup(esp, (char *)b.data, len);
643 NT_STATUS_HAVE_NO_MEMORY(line);
645 p = strchr(line,'=');
648 esp_putvar(esp, line, p+1);
663 parse the variables in a GET style request
665 static NTSTATUS http_parse_get(struct esp_state *esp)
667 struct websrv_context *web = esp->web;
671 p = strchr(web->input.url, '?');
672 web->input.query_string = p+1;
675 s = talloc_strdup(esp, esp->web->input.query_string);
676 NT_STATUS_HAVE_NO_MEMORY(s);
678 for (tok=strtok_r(s,"&;", &pp);tok;tok=strtok_r(NULL,"&;", &pp)) {
682 esp_putvar(esp, tok, p+1);
689 called when a session times out
691 static void session_timeout(struct event_context *ev, struct timed_event *te,
692 struct timeval t, void *private)
694 struct session_data *s = talloc_get_type(private, struct session_data);
701 static int session_destructor(struct session_data *s)
703 DLIST_REMOVE(s->edata->sessions, s);
708 setup the session for this request
710 static void http_setup_session(struct esp_state *esp)
712 const char *session_key = SWAT_SESSION_KEY;
714 const char *cookie = esp->web->input.cookie;
715 const char *key = NULL;
716 struct esp_data *edata = talloc_get_type(esp->web->task->private, struct esp_data);
717 struct session_data *s;
718 BOOL generated_key = False;
720 /* look for our session key */
721 if (cookie && (p = strstr(cookie, session_key)) &&
722 p[strlen(session_key)] == '=') {
723 p += strlen(session_key)+1;
724 key = talloc_strndup(esp, p, strcspn(p, ";"));
727 if (key == NULL && esp->web->input.session_key) {
728 key = esp->web->input.session_key;
729 } else if (key == NULL) {
730 key = generate_random_str_list(esp, 16, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
731 generated_key = True;
734 /* try to find this session in the existing session list */
735 for (s=edata->sessions;s;s=s->next) {
736 if (strcmp(key, s->id) == 0) {
742 /* create a new session */
743 s = talloc_zero(edata, struct session_data);
744 s->id = talloc_steal(s, key);
748 s->lifetime = lp_parm_int(-1, "web", "sessiontimeout", 900);
749 DLIST_ADD(edata->sessions, s);
750 talloc_set_destructor(s, session_destructor);
751 if (!generated_key) {
752 mprSetPropertyValue(&esp->variables[ESP_REQUEST_OBJ],
753 "SESSION_EXPIRED", mprCreateStringVar("True", 0));
757 http_setCookie(esp->web, session_key, key, s->lifetime, "/", 0);
760 mprCopyVar(&esp->variables[ESP_SESSION_OBJ], s->data, MPR_DEEP_COPY);
763 esp->web->session = s;
767 /* callbacks for esp processing */
768 static const struct Esp esp_control = {
769 .maxScriptSize = 60000,
770 .writeBlock = http_writeBlock,
771 .setHeader = http_setHeader,
772 .redirect = http_redirect,
773 .setResponseCode = http_setResponseCode,
774 .readFile = http_readFile,
775 .mapToStorage = http_mapToStorage,
776 .setCookie = http_setCookie,
777 .createSession = http_createSession,
778 .destroySession = http_destroySession,
779 .getSessionId = http_getSessionId
783 process a complete http request
785 void http_process_input(struct websrv_context *web)
788 struct esp_state *esp = NULL;
789 struct esp_data *edata = talloc_get_type(web->task->private, struct esp_data);
790 struct smbcalls_context *smbcalls_ctx;
792 void *save_mpr_ctx = mprMemCtx();
793 void *ejs_save = ejs_save_state();
795 const char *file_type = NULL;
801 enum page_type page_type;
803 const char *extension;
804 const char *mime_type;
805 enum page_type page_type;
807 {"gif", "image/gif"},
808 {"png", "image/png"},
809 {"jpg", "image/jpeg"},
810 {"txt", "text/plain"},
811 {"ico", "image/x-icon"},
813 {"esp", "text/html", True}
817 * give the smbcalls a chance to find the event context
818 * and messaging context
820 smbcalls_ctx = talloc(web, struct smbcalls_context);
821 if (smbcalls_ctx == NULL) goto internal_error;
822 smbcalls_ctx->event_ctx = web->conn->event.ctx;
823 smbcalls_ctx->msg_ctx = web->conn->msg_ctx;
825 esp = talloc_zero(smbcalls_ctx, struct esp_state);
826 if (esp == NULL) goto internal_error;
832 if (espOpen(&esp_control) != 0) goto internal_error;
834 for (i=0;i<ARRAY_SIZE(esp->variables);i++) {
835 esp->variables[i] = mprCreateUndefinedVar();
837 esp->variables[ESP_HEADERS_OBJ] = mprCreateObjVar("headers", ESP_HASH_SIZE);
838 esp->variables[ESP_FORM_OBJ] = mprCreateObjVar("form", ESP_HASH_SIZE);
839 esp->variables[ESP_APPLICATION_OBJ] = mprCreateObjVar("application", ESP_HASH_SIZE);
840 esp->variables[ESP_COOKIES_OBJ] = mprCreateObjVar("cookies", ESP_HASH_SIZE);
841 esp->variables[ESP_FILES_OBJ] = mprCreateObjVar("files", ESP_HASH_SIZE);
842 esp->variables[ESP_REQUEST_OBJ] = mprCreateObjVar("request", ESP_HASH_SIZE);
843 esp->variables[ESP_SERVER_OBJ] = mprCreateObjVar("server", ESP_HASH_SIZE);
844 esp->variables[ESP_SESSION_OBJ] = mprCreateObjVar("session", ESP_HASH_SIZE);
846 if (edata->application_data) {
847 mprCopyVar(&esp->variables[ESP_APPLICATION_OBJ],
848 edata->application_data, MPR_DEEP_COPY);
851 smb_setup_ejs_functions(web_server_ejs_exception);
853 if (web->input.url == NULL) {
854 http_error(web, 400, "You must specify a GET or POST request");
855 mprSetCtx(save_mpr_ctx);
856 ejs_restore_state(ejs_save);
860 /* parse any form or get variables */
861 if (web->input.post_request) {
862 status = http_parse_post(esp);
863 if (!NT_STATUS_IS_OK(status)) {
864 http_error(web, 400, "Malformed POST data");
865 mprSetCtx(save_mpr_ctx);
866 ejs_restore_state(ejs_save);
870 if (strchr(web->input.url, '?')) {
871 status = http_parse_get(esp);
872 if (!NT_STATUS_IS_OK(status)) {
873 http_error(web, 400, "Malformed GET data");
874 mprSetCtx(save_mpr_ctx);
875 ejs_restore_state(ejs_save);
880 http_setup_session(esp);
882 esp->req = espCreateRequest(web, web->input.url, esp->variables);
883 if (esp->req == NULL) goto internal_error;
886 * Work out the mime type. First, we see if the request is a JSON-RPC
887 * service request. If not, we look at the extension.
889 if (strncmp(web->input.url,
891 sizeof(JSONRPC_REQUEST) - 1) == 0 &&
892 (web->input.url[sizeof(JSONRPC_REQUEST) - 1] == '\0' ||
893 web->input.url[sizeof(JSONRPC_REQUEST) - 1] == '/')) {
894 page_type = page_type_jsonrpc;
895 file_type = "text/json";
898 p = strrchr(web->input.url, '.');
900 page_type = page_type_esp;
901 file_type = "text/html";
903 for (i=0;p && i<ARRAY_SIZE(mime_types);i++) {
904 if (strcmp(mime_types[i].extension, p+1) == 0) {
905 page_type = mime_types[i].page_type;
906 file_type = mime_types[i].mime_type;
909 if (file_type == NULL) {
910 page_type = page_type_simple;
911 file_type = "text/html";
915 /* setup basic headers */
916 http_setResponseCode(web, 200);
917 http_setHeader(web, talloc_asprintf(esp, "Date: %s",
918 http_timestring(esp, time(NULL))), 0);
919 http_setHeader(web, "Server: Samba", 0);
920 http_setHeader(web, "Connection: close", 0);
921 http_setHeader(web, talloc_asprintf(esp, "Content-Type: %s", file_type), 0);
923 http_setup_arrays(esp);
926 * Do pre-authentication. If pre-authentication succeeds, do
927 * page-type-specific processing.
931 case page_type_simple:
932 if (http_preauth(esp)) {
933 http_simple_request(web);
938 if (http_preauth(esp)) {
939 esp_request(esp, web->input.url);
943 case page_type_jsonrpc:
944 jsonrpc_request(esp);
948 if (web->conn == NULL) {
949 /* the connection has been terminated above us, probably
954 if (!web->output.output_pending) {
955 http_output_headers(web);
956 EVENT_FD_WRITEABLE(web->conn->event.fde);
957 web->output.output_pending = True;
960 /* copy any application data to long term storage in edata */
961 talloc_free(edata->application_data);
962 edata->application_data = talloc_zero(edata, struct MprVar);
963 mprSetCtx(edata->application_data);
964 mprCopyVar(edata->application_data, &esp->variables[ESP_APPLICATION_OBJ],
968 /* copy any session data */
970 talloc_free(web->session->data);
971 web->session->data = talloc_zero(web->session, struct MprVar);
972 if (esp->variables[ESP_SESSION_OBJ].properties == NULL ||
973 esp->variables[ESP_SESSION_OBJ].properties[0].numItems == 0) {
974 talloc_free(web->session);
977 mprSetCtx(web->session->data);
978 mprCopyVar(web->session->data, &esp->variables[ESP_SESSION_OBJ],
980 /* setup the timeout for the session data */
982 talloc_free(web->session->te);
983 web->session->te = event_add_timed(web->conn->event.ctx, web->session,
984 timeval_current_ofs(web->session->lifetime, 0),
985 session_timeout, web->session);
990 mprSetCtx(save_mpr_ctx);
991 ejs_restore_state(ejs_save);
997 if (web->conn != NULL) {
998 http_error(web, 500, "Internal server error");
1000 mprSetCtx(save_mpr_ctx);
1001 ejs_restore_state(ejs_save);
1006 parse one line of header input
1008 NTSTATUS http_parse_header(struct websrv_context *web, const char *line)
1011 web->input.end_of_headers = True;
1012 } else if (strncasecmp(line,"GET ", 4)==0) {
1013 web->input.url = talloc_strndup(web, &line[4], strcspn(&line[4], " \t"));
1014 } else if (strncasecmp(line,"POST ", 5)==0) {
1015 web->input.post_request = True;
1016 web->input.url = talloc_strndup(web, &line[5], strcspn(&line[5], " \t"));
1017 } else if (strchr(line, ':') == NULL) {
1018 http_error(web, 400, "This server only accepts GET and POST requests");
1019 return NT_STATUS_INVALID_PARAMETER;
1020 } else if (strncasecmp(line,"Content-Length: ", 16)==0) {
1021 web->input.content_length = strtoul(&line[16], NULL, 10);
1023 #define PULL_HEADER(v, s) do { \
1024 if (strncmp(line, s, strlen(s)) == 0) { \
1025 web->input.v = talloc_strdup(web, &line[strlen(s)]); \
1026 return NT_STATUS_OK; \
1029 PULL_HEADER(content_type, "Content-Type: ");
1030 PULL_HEADER(user_agent, "User-Agent: ");
1031 PULL_HEADER(referer, "Referer: ");
1032 PULL_HEADER(host, "Host: ");
1033 PULL_HEADER(accept_encoding, "Accept-Encoding: ");
1034 PULL_HEADER(accept_language, "Accept-Language: ");
1035 PULL_HEADER(accept_charset, "Accept-Charset: ");
1036 PULL_HEADER(cookie, "Cookie: ");
1039 /* ignore all other headers for now */
1040 return NT_STATUS_OK;
1045 setup the esp processor - called at task initialisation
1047 NTSTATUS http_setup_esp(struct task_server *task)
1049 struct esp_data *edata;
1051 edata = talloc_zero(task, struct esp_data);
1052 NT_STATUS_HAVE_NO_MEMORY(edata);
1054 task->private = edata;
1056 edata->tls_params = tls_initialise(edata);
1057 NT_STATUS_HAVE_NO_MEMORY(edata->tls_params);
1059 return NT_STATUS_OK;