web_server: Remove the unused Python WSGI web server
authorGarming Sam <garming@catalyst.net.nz>
Wed, 6 Mar 2019 00:06:50 +0000 (13:06 +1300)
committerJeremy Allison <jra@samba.org>
Thu, 7 Mar 2019 00:33:16 +0000 (00:33 +0000)
SWAT was removed in Samba 4.1 and there isn't any reason to keep a web
server in our codebase. The web server was not turned on by default.

The web server plainly does not hold up to modern web server standards
and allows for resource exhaustion (and probably generally has bugs).
Credit goes to Michael Hanselmann for prompting us to remove this
service entirely.

Signed-off-by: Garming Sam <garming@catalyst.net.nz>
Reviewed-by: Jeremy Allison <jra@samba.org>
python/samba/web_server/__init__.py [deleted file]
source4/web_server/web_server.c [deleted file]
source4/web_server/web_server.h [deleted file]
source4/web_server/wscript_build [deleted file]
source4/web_server/wsgi.c [deleted file]
wscript_build

diff --git a/python/samba/web_server/__init__.py b/python/samba/web_server/__init__.py
deleted file mode 100644 (file)
index 96214f6..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Unix SMB/CIFS implementation.
-# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
-#
-# Implementation of SWAT that uses WSGI
-#
-# 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/>.
-#
-
-from __future__ import print_function
-
-def render_placeholder(environ, start_response):
-    """Send the user a simple placeholder about missing SWAT."""
-    status = '200 OK'
-    response_headers = [('Content-type', 'text/html')]
-    start_response(status, response_headers)
-
-    yield b"<!doctype html>\n"
-    yield b"<html>\n"
-    yield b"  <title>The Samba web service</title>\n"
-    yield b"</html>\n"
-
-    yield b"<body>\n"
-    yield b"<p>Welcome to this Samba web server.</p>\n"
-    yield b"<p>This page is a simple placeholder. You probably want to install "
-    yield b"SWAT. More information can be found "
-    yield b"<a href='http://wiki.samba.org/index.php/SWAT2'>on the wiki</a>.</p>"
-    yield b"</p>\n"
-    yield b"</body>\n"
-    yield b"</html>\n"
-
-
-def __call__(environ, start_response):
-    """Handle a HTTP request."""
-    from wsgiref.util import application_uri, shift_path_info
-    from samba.compat import urllib_join
-
-    try:
-        import swat
-    except ImportError as e:
-        print("NO SWAT: %r" % e)
-        have_swat = False
-    else:
-        have_swat = True
-
-    orig_path = environ['PATH_INFO']
-    name = shift_path_info(environ)
-
-    if name == "":
-        if have_swat:
-            start_response('301 Redirect',
-                           [('Location', urllib_join(application_uri(environ), 'swat')), ])
-            return []
-        else:
-            return render_placeholder(environ, start_response)
-    elif have_swat and name == "swat":
-        return swat.__call__(environ, start_response)
-    else:
-        status = '404 Not found'
-        response_headers = [('Content-type', 'text/html')]
-        start_response(status, response_headers)
-        return [("The path %s (%s) was not found" % (orig_path, name)).encode('iso-8859-1')]
-
-
-if __name__ == '__main__':
-    from wsgiref import simple_server
-    httpd = simple_server.make_server('localhost', 8090, __call__)
-    print("Serving HTTP on port 8090...")
-    httpd.serve_forever()
diff --git a/source4/web_server/web_server.c b/source4/web_server/web_server.c
deleted file mode 100644 (file)
index a1db34b..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-
-   web server startup
-
-   Copyright (C) Andrew Tridgell 2005
-   Copyright (C) Jelmer Vernooij 2008
-   
-   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 "web_server/web_server.h"
-#include "../lib/util/dlinklist.h"
-#include "lib/tls/tls.h"
-#include "lib/events/events.h"
-#include "lib/socket/netif.h"
-#include "param/param.h"
-
-NTSTATUS server_service_web_init(TALLOC_CTX *);
-
-/* don't allow connections to hang around forever */
-#define HTTP_TIMEOUT 120
-
-/*
-  destroy a web connection
-*/
-static int websrv_destructor(struct websrv_context *web)
-{
-       return 0;
-}
-
-/*
-  called when a connection times out. This prevents a stuck connection
-  from hanging around forever
-*/
-static void websrv_timeout(struct tevent_context *event_context, 
-                          struct tevent_timer *te, 
-                          struct timeval t, void *private_data)
-{
-       struct websrv_context *web = talloc_get_type_abort(private_data, struct websrv_context);
-       struct stream_connection *conn = web->conn;
-       web->conn = NULL;
-       /* TODO: send a message to any running esp context on this connection
-          to stop running */
-       stream_terminate_connection(conn, "websrv_timeout: timed out"); 
-}
-
-/*
-  setup for a raw http level error
-*/
-void http_error(struct websrv_context *web, const char *status, const char *info)
-{
-       char *s;
-       s = talloc_asprintf(web,"<HTML><HEAD><TITLE>Error %s</TITLE></HEAD><BODY><H1>Error %s</H1><pre>%s</pre><p></BODY></HTML>\r\n\r\n", 
-                           status, status, info);
-       if (s == NULL) {
-               stream_terminate_connection(web->conn, "http_error: out of memory");
-               return;
-       }
-       websrv_output_headers(web, status, NULL);
-       websrv_output(web, s, strlen(s));
-}
-
-void websrv_output_headers(struct websrv_context *web, const char *status, struct http_header *headers)
-{
-       char *s;
-       DATA_BLOB b;
-       struct http_header *hdr;
-
-       s = talloc_asprintf(web, "HTTP/1.0 %s\r\n", status);
-       if (s == NULL) return;
-       for (hdr = headers; hdr; hdr = hdr->next) {
-               s = talloc_asprintf_append_buffer(s, "%s: %s\r\n", hdr->name, hdr->value);
-       }
-
-       s = talloc_asprintf_append_buffer(s, "\r\n");
-
-       b = web->output.content;
-       web->output.content = data_blob_string_const(s);
-       websrv_output(web, b.data, b.length);
-       data_blob_free(&b);
-}
-
-void websrv_output(struct websrv_context *web, const void *data, size_t length)
-{
-       data_blob_append(web, &web->output.content, data, length);
-       TEVENT_FD_NOT_READABLE(web->conn->event.fde);
-       TEVENT_FD_WRITEABLE(web->conn->event.fde);
-       web->output.output_pending = true;
-}
-
-
-/*
-  parse one line of header input
-*/
-NTSTATUS http_parse_header(struct websrv_context *web, const char *line)
-{
-       int error = 0;
-
-       if (line[0] == 0) {
-               web->input.end_of_headers = true;
-       } else if (strncasecmp(line,"GET ", 4)==0) {
-               web->input.url = talloc_strndup(web, &line[4], strcspn(&line[4], " \t"));
-       } else if (strncasecmp(line,"POST ", 5)==0) {
-               web->input.post_request = true;
-               web->input.url = talloc_strndup(web, &line[5], strcspn(&line[5], " \t"));
-       } else if (strchr(line, ':') == NULL) {
-               http_error(web, "400 Bad request", "This server only accepts GET and POST requests");
-               return NT_STATUS_INVALID_PARAMETER;
-       } else if (strncasecmp(line, "Content-Length: ", 16)==0) {
-               web->input.content_length = strtoul_err(&line[16], NULL, 10, &error);
-               if (error != 0) {
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
-       } else {
-               struct http_header *hdr = talloc_zero(web, struct http_header);
-               char *colon = strchr(line, ':');
-               if (colon == NULL) {
-                       http_error(web, "500 Internal Server Error", "invalidly formatted header");
-                       return NT_STATUS_INVALID_PARAMETER;
-               }
-
-               hdr->name = talloc_strndup(hdr, line, colon-line);
-               hdr->value = talloc_strdup(hdr, colon+1);
-               DLIST_ADD(web->input.headers, hdr);
-       }
-
-       /* ignore all other headers for now */
-       return NT_STATUS_OK;
-}
-
-/*
-  called when a web connection becomes readable
-*/
-static void websrv_recv(struct stream_connection *conn, uint16_t flags)
-{
-       struct web_server_data *wdata;
-       struct websrv_context *web = talloc_get_type_abort(conn->private_data,
-                                                          struct websrv_context);
-       NTSTATUS status;
-       uint8_t buf[1024];
-       size_t nread;
-       uint8_t *p;
-       DATA_BLOB b;
-
-       /* not the most efficient http parser ever, but good enough for us */
-       status = socket_recv(conn->socket, buf, sizeof(buf), &nread);
-       if (NT_STATUS_IS_ERR(status)) goto failed;
-       if (!NT_STATUS_IS_OK(status)) return;
-
-       if (!data_blob_append(web, &web->input.partial, buf, nread))
-               goto failed;
-
-       /* parse any lines that are available */
-       b = web->input.partial;
-       while (!web->input.end_of_headers &&
-              (p=(uint8_t *)memchr(b.data, '\n', b.length))) {
-               const char *line = (const char *)b.data;
-               *p = 0;
-               if (p != b.data && p[-1] == '\r') {
-                       p[-1] = 0;
-               }
-               status = http_parse_header(web, line);
-               if (!NT_STATUS_IS_OK(status)) return;
-               b.length -= (p - b.data) + 1;
-               b.data = p+1;
-       }
-
-       /* keep any remaining bytes in web->input.partial */
-       if (b.length == 0) {
-               b.data = NULL;
-       }
-       b = data_blob_talloc(web, b.data, b.length);
-       data_blob_free(&web->input.partial);
-       web->input.partial = b;
-
-       /* we finish when we have both the full headers (terminated by
-          a blank line) and any post data, as indicated by the
-          content_length */
-       if (web->input.end_of_headers &&
-           web->input.partial.length >= web->input.content_length) {
-               if (web->input.partial.length > web->input.content_length) {
-                       web->input.partial.data[web->input.content_length] = 0;
-               }
-               TEVENT_FD_NOT_READABLE(web->conn->event.fde);
-
-               /* the reference/unlink code here is quite subtle. It
-                is needed because the rendering of the web-pages, and
-                in particular the esp/ejs backend, is semi-async.  So
-                we could well end up in the connection timeout code
-                while inside http_process_input(), but we must not
-                destroy the stack variables being used by that
-                rendering process when we handle the timeout. */
-               if (!talloc_reference(web->task, web)) goto failed;
-               wdata = talloc_get_type_abort(web->task->private_data, struct web_server_data);
-               if (wdata == NULL) goto failed;
-               wdata->http_process_input(wdata, web);
-               talloc_unlink(web->task, web);
-       }
-       return;
-
-failed:
-       stream_terminate_connection(conn, "websrv_recv: failed");
-}
-
-
-
-/*
-  called when a web connection becomes writable
-*/
-static void websrv_send(struct stream_connection *conn, uint16_t flags)
-{
-       struct websrv_context *web = talloc_get_type_abort(conn->private_data,
-                                                          struct websrv_context);
-       NTSTATUS status;
-       size_t nsent;
-       DATA_BLOB b;
-
-       b = web->output.content;
-       b.data += web->output.nsent;
-       b.length -= web->output.nsent;
-
-       status = socket_send(conn->socket, &b, &nsent);
-       if (NT_STATUS_IS_ERR(status)) {
-               stream_terminate_connection(web->conn, "socket_send: failed");
-               return;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               return;
-       }
-
-       web->output.nsent += nsent;
-
-       if (web->output.content.length == web->output.nsent) {
-               stream_terminate_connection(web->conn, "websrv_send: finished sending");
-       }
-}
-
-/*
-  establish a new connection to the web server
-*/
-static void websrv_accept(struct stream_connection *conn)
-{
-       struct web_server_data *wdata = talloc_get_type_abort(conn->private_data, struct web_server_data);
-       struct websrv_context *web;
-       struct socket_context *tls_socket;
-
-       web = talloc_zero(conn, struct websrv_context);
-       if (web == NULL) goto failed;
-
-       web->task = wdata->task;
-       web->conn = conn;
-       conn->private_data = web;
-       talloc_set_destructor(web, websrv_destructor);
-
-       tevent_add_timer(conn->event.ctx, web,
-                       timeval_current_ofs(HTTP_TIMEOUT, 0),
-                       websrv_timeout, web);
-
-       /* Overwrite the socket with a (possibly) TLS socket */
-       tls_socket = tls_init_server(wdata->tls_params, conn->socket, 
-                                    conn->event.fde, "GPHO");
-       /* We might not have TLS, or it might not have initilised */
-       if (tls_socket) {
-               talloc_unlink(conn, conn->socket);
-               talloc_steal(conn, tls_socket);
-               conn->socket = tls_socket;
-       } else {
-               DEBUG(3, ("TLS not available for web_server connections\n"));
-       }
-
-       return;
-
-failed:
-       talloc_free(conn);
-}
-
-
-static const struct stream_server_ops web_stream_ops = {
-       .name                   = "web",
-       .accept_connection      = websrv_accept,
-       .recv_handler           = websrv_recv,
-       .send_handler           = websrv_send,
-};
-
-/*
-  startup the web server task
-*/
-static NTSTATUS websrv_task_init(struct task_server *task)
-{
-       NTSTATUS status;
-       uint16_t port = lpcfg_web_port(task->lp_ctx);
-       struct web_server_data *wdata;
-
-       task_server_set_title(task, "task[websrv]");
-
-       /* startup the Python processor - unfortunately we can't do this
-          per connection as that wouldn't allow for session variables */
-       wdata = talloc_zero(task, struct web_server_data);
-       if (wdata == NULL) {
-               status = NT_STATUS_NO_MEMORY;
-               goto failed;
-       }
-
-       wdata->task = task;
-       task->private_data = wdata;
-
-       if (lpcfg_interfaces(task->lp_ctx) && lpcfg_bind_interfaces_only(task->lp_ctx)) {
-               int num_interfaces;
-               int i;
-               struct interface *ifaces;
-
-               load_interface_list(NULL, task->lp_ctx, &ifaces);
-
-               num_interfaces = iface_list_count(ifaces);
-               for(i = 0; i < num_interfaces; i++) {
-                       const char *address = iface_list_n_ip(ifaces, i);
-                       status = stream_setup_socket(task,
-                                                    task->event_ctx,
-                                                    task->lp_ctx,
-                                                    task->model_ops,
-                                                    &web_stream_ops,
-                                                    "ip", address,
-                                                    &port,
-                                                    lpcfg_socket_options(task->lp_ctx),
-                                                    task,
-                                                    task->process_context);
-                       if (!NT_STATUS_IS_OK(status)) goto failed;
-               }
-
-               talloc_free(ifaces);
-       } else {
-               char **wcard;
-               int i;
-               wcard = iface_list_wildcard(task);
-               if (wcard == NULL) {
-                       DEBUG(0,("No wildcard addresses available\n"));
-                       status = NT_STATUS_UNSUCCESSFUL;
-                       goto failed;
-               }
-               for (i=0; wcard[i]; i++) {
-                       status = stream_setup_socket(task, task->event_ctx,
-                                                    task->lp_ctx,
-                                                    task->model_ops,
-                                                    &web_stream_ops,
-                                                    "ip", wcard[i],
-                                                    &port, lpcfg_socket_options(task->lp_ctx),
-                                                    wdata,
-                                                    task->process_context);
-                       if (!NT_STATUS_IS_OK(status)) goto failed;
-               }
-               talloc_free(wcard);
-       }
-
-       wdata->tls_params = tls_initialise(wdata, task->lp_ctx);
-       if (wdata->tls_params == NULL) {
-               status = NT_STATUS_UNSUCCESSFUL;
-               goto failed;
-       }
-
-       if (!wsgi_initialize(wdata)) {
-               status = NT_STATUS_UNSUCCESSFUL;
-               goto failed;
-       }
-
-
-       return NT_STATUS_OK;
-
-failed:
-       task_server_terminate(task, "websrv_task_init: failed to startup web server task", true);
-       return status;
-}
-
-
-/* called at smbd startup - register ourselves as a server service */
-NTSTATUS server_service_web_init(TALLOC_CTX *ctx)
-{
-       static const struct service_details details = {
-               .inhibit_fork_on_accept = true,
-               .inhibit_pre_fork = true,
-               .task_init = websrv_task_init,
-               .post_fork = NULL
-       };
-       return register_server_service(ctx, "web", &details);
-}
diff --git a/source4/web_server/web_server.h b/source4/web_server/web_server.h
deleted file mode 100644 (file)
index 9f21359..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   
-   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/>.
-*/
-
-#ifndef __WEB_SERVER_H__
-#define __WEB_SERVER_H__
-
-#include "smbd/process_model.h"
-
-struct websrv_context;
-
-struct web_server_data {
-       struct tls_params *tls_params;
-       void (*http_process_input)(struct web_server_data *wdata, 
-                                  struct websrv_context *web);
-       void *private_data;
-       struct task_server *task;
-};
-
-struct http_header {
-       char *name;
-       char *value;
-       struct http_header *prev, *next;
-};
-
-/*
-  context of one open web connection
-*/
-struct websrv_context {
-       struct task_server *task;
-       struct stream_connection *conn;
-       struct websrv_request_input {
-               bool tls_detect;
-               bool tls_first_char;
-               uint8_t first_byte;
-               DATA_BLOB partial;
-               bool end_of_headers;
-               char *url;
-               unsigned content_length;
-               bool post_request;
-               struct http_header *headers;
-       } input;
-       struct websrv_request_output {
-               bool output_pending;
-               DATA_BLOB content;
-               bool headers_sent;
-               unsigned nsent;
-       } output;
-       struct session_data *session;
-};
-
-bool wsgi_initialize(struct web_server_data *wdata);
-void http_error(struct websrv_context *web, const char *status, const char *info);
-void websrv_output_headers(struct websrv_context *web, const char *status, struct http_header *headers);
-void websrv_output(struct websrv_context *web, const void *data, size_t length);
-NTSTATUS http_parse_header(struct websrv_context *web, const char *line);
-
-#endif /* __WEB_SERVER_H__ */
diff --git a/source4/web_server/wscript_build b/source4/web_server/wscript_build
deleted file mode 100644 (file)
index 97c550b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-
-libpython = bld.pyembed_libname('LIBPYTHON')
-
-bld.SAMBA_SUBSYSTEM('WEB_WSGI',
-               source='wsgi.c',
-               pyext=True,
-               deps='talloc LIBTSOCKET',
-               enabled=bld.AD_DC_BUILD_IS_ENABLED()
-               )
-
-
-bld.SAMBA_MODULE('service_web',
-               source='web_server.c',
-               subsystem='service',
-               init_function='server_service_web_init',
-               deps='LIBTLS process_model %s WEB_WSGI' % libpython,
-               pyembed=True,
-               internal_module=False,
-               enabled=bld.AD_DC_BUILD_IS_ENABLED()
-               )
diff --git a/source4/web_server/wsgi.c b/source4/web_server/wsgi.c
deleted file mode 100644 (file)
index a2499af..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-/* 
-   Unix SMB/CIFS implementation.
-   Samba utility functions
-   Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
-
-   Implementation of the WSGI interface described in PEP0333 
-   (http://www.python.org/dev/peps/pep-0333)
-
-   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 <Python.h>
-#include "includes.h"
-#include "web_server/web_server.h"
-#include "../lib/util/dlinklist.h"
-#include "lib/tls/tls.h"
-#include "lib/tsocket/tsocket.h"
-#include "python/modules.h"
-#include "python/py3compat.h"
-
-typedef struct {
-       PyObject_HEAD
-       struct websrv_context *web;
-} web_request_Object;
-
-static PyObject *start_response(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-       PyObject *response_header, *exc_info = NULL;
-       char *status;
-       Py_ssize_t i;
-       const char *kwnames[] = {
-               "status", "response_header", "exc_info", NULL
-       };
-       web_request_Object *py_web = (web_request_Object *)self;
-       struct websrv_context *web = py_web->web;
-       struct http_header *headers = NULL;
-
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O:start_response", discard_const_p(char *, kwnames), &status, &response_header, &exc_info)) {
-               return NULL;
-       }
-
-       /* FIXME: exc_info */
-
-       if (!PyList_Check(response_header)) {
-               PyErr_SetString(PyExc_TypeError, "response_header should be list");
-               return NULL;
-       }
-
-       for (i = 0; i < PyList_Size(response_header); i++) {
-               struct http_header *hdr = talloc_zero(web, struct http_header);
-               PyObject *item = PyList_GetItem(response_header, i);
-               PyObject *py_name, *py_value;
-
-               if (!PyTuple_Check(item)) {
-                       PyErr_SetString(PyExc_TypeError, "Expected tuple");
-                       return NULL;
-               }
-
-               if (PyTuple_Size(item) != 2) {
-                       PyErr_SetString(PyExc_TypeError, "header tuple has invalid size, expected 2");
-                       return NULL;
-               }
-
-               py_name = PyTuple_GetItem(item, 0);
-
-               if (!PyStr_Check(py_name)) {
-                       PyErr_SetString(PyExc_TypeError, "header name should be string");
-                       return NULL;
-               }
-
-               py_value = PyTuple_GetItem(item, 1);
-               if (!PyStr_Check(py_value)) {
-                       PyErr_SetString(PyExc_TypeError, "header value should be string");
-                       return NULL;
-               }
-
-               hdr->name = talloc_strdup(hdr, PyStr_AsString(py_name));
-               hdr->value = talloc_strdup(hdr, PyStr_AsString(py_value));
-               DLIST_ADD(headers, hdr);
-       }
-
-       websrv_output_headers(web, status, headers);
-
-       Py_RETURN_NONE;
-}
-
-static PyMethodDef web_request_methods[] = {
-       { "start_response", (PyCFunction)start_response, METH_VARARGS|METH_KEYWORDS, NULL },
-       { NULL }
-};
-
-
-PyTypeObject web_request_Type = {
-       PyVarObject_HEAD_INIT(NULL, 0)
-       .tp_name = "wsgi.Request",
-       .tp_methods = web_request_methods,
-       .tp_basicsize = sizeof(web_request_Object),
-       .tp_flags = Py_TPFLAGS_DEFAULT,
-};
-
-typedef struct {
-       PyObject_HEAD
-} error_Stream_Object;
-
-static PyObject *py_error_flush(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-       /* Nothing to do here */
-       Py_RETURN_NONE;
-}
-
-static PyObject *py_error_write(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-       const char *kwnames[] = { "str", NULL };
-       char *str = NULL;
-
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:write", discard_const_p(char *, kwnames), &str)) {
-               return NULL;
-       }
-
-       DEBUG(0, ("%s", str));
-
-       Py_RETURN_NONE;
-}
-
-static PyObject *py_error_writelines(PyObject *self, PyObject *args, PyObject *kwargs)
-{
-       const char *kwnames[] = { "seq", NULL };
-       PyObject *seq = NULL, *item;
-
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:writelines", discard_const_p(char *, kwnames), &seq)) {
-               return NULL;
-       }
-
-       while ((item = PyIter_Next(seq))) {
-               const char *str = NULL;
-               Py_ssize_t size = 0;
-               if (!IsPy3Bytes(item)) {
-                       str = PyStr_AsUTF8AndSize(item, &size);
-               } else {
-                       str = PyBytes_AsString(item);
-                       size = PyBytes_Size(item);
-               }
-               if (size > 0) {
-                       DEBUG(0, ("%s", str));
-               }
-       }
-
-       Py_RETURN_NONE;
-}
-
-static PyMethodDef error_Stream_methods[] = {
-       { "flush", (PyCFunction)py_error_flush, METH_VARARGS|METH_KEYWORDS, NULL },
-       { "write", (PyCFunction)py_error_write, METH_VARARGS|METH_KEYWORDS, NULL },
-       { "writelines", (PyCFunction)py_error_writelines, METH_VARARGS|METH_KEYWORDS, NULL },
-       { NULL, NULL, 0, NULL }
-};
-
-PyTypeObject error_Stream_Type = {
-       PyVarObject_HEAD_INIT(NULL, 0)
-       .tp_name = "wsgi.ErrorStream",
-       .tp_basicsize = sizeof(error_Stream_Object),
-       .tp_methods = error_Stream_methods,
-       .tp_flags = Py_TPFLAGS_DEFAULT,
-};
-
-typedef struct {
-       PyObject_HEAD
-       struct websrv_context *web;
-       size_t offset;
-} input_Stream_Object;
-
-static PyObject *py_input_read(PyObject *_self, PyObject *args, PyObject *kwargs)
-{
-       const char *kwnames[] = { "size", NULL };
-       PyObject *ret;
-       input_Stream_Object *self = (input_Stream_Object *)_self;
-       int size = -1;
-
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", discard_const_p(char *, kwnames), &size))
-               return NULL;
-       
-       /* Don't read beyond buffer boundaries */
-       if (size == -1)
-               size = self->web->input.partial.length-self->offset;
-       else
-               size = MIN(size, self->web->input.partial.length-self->offset);
-
-       ret = PyBytes_FromStringAndSize((char *)self->web->input.partial.data+self->offset, size);
-       self->offset += size;
-
-       return ret;
-}
-
-static PyObject *py_input_readline(PyObject *_self)
-{
-       /* FIXME */
-       PyErr_SetString(PyExc_NotImplementedError, 
-                       "readline() not yet implemented");
-       return NULL;
-}
-
-static PyObject *py_input_readlines(PyObject *_self, PyObject *args, PyObject *kwargs)
-{
-       const char *kwnames[] = { "hint", NULL };
-       int hint = 0;
-
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", discard_const_p(char *, kwnames), &hint))
-               return NULL;
-       
-       /* FIXME */
-       PyErr_SetString(PyExc_NotImplementedError, 
-                       "readlines() not yet implemented");
-       return NULL;
-}
-
-static PyObject *py_input___iter__(PyObject *_self)
-{
-       /* FIXME */
-       PyErr_SetString(PyExc_NotImplementedError, 
-                       "__iter__() not yet implemented");
-       return NULL;
-}
-
-static PyMethodDef input_Stream_methods[] = {
-       { "read", (PyCFunction)py_input_read, METH_VARARGS|METH_KEYWORDS, NULL },
-       { "readline", (PyCFunction)py_input_readline, METH_NOARGS, NULL },
-       { "readlines", (PyCFunction)py_input_readlines, METH_VARARGS|METH_KEYWORDS, NULL },
-       { "__iter__", (PyCFunction)py_input___iter__, METH_NOARGS, NULL },
-       { NULL, NULL, 0, NULL }
-};
-
-PyTypeObject input_Stream_Type = {
-       PyVarObject_HEAD_INIT(NULL, 0)
-       .tp_name = "wsgi.InputStream",
-       .tp_basicsize = sizeof(input_Stream_Object),
-       .tp_methods = input_Stream_methods,
-       .tp_flags = Py_TPFLAGS_DEFAULT,
-};
-
-static PyObject *Py_InputHttpStream(struct websrv_context *web)
-{
-       input_Stream_Object *ret = PyObject_New(input_Stream_Object, &input_Stream_Type);
-       ret->web = web;
-       ret->offset = 0;
-       return (PyObject *)ret;
-}
-
-static PyObject *Py_ErrorHttpStream(void)
-{
-       error_Stream_Object *ret = PyObject_New(error_Stream_Object, &error_Stream_Type);
-       return (PyObject *)ret;
-}
-
-static void DEBUG_Print_PyError(int level, const char *message)
-{
-       PyObject *old_stderr, *new_stderr;
-       PyObject *sys_module;
-       PyObject *ptype, *pvalue, *ptb;
-
-       PyErr_Fetch(&ptype, &pvalue, &ptb);
-
-       DEBUG(0, ("WSGI: Server exception occurred: %s\n", message));
-
-       sys_module = PyImport_ImportModule("sys");
-       if (sys_module == NULL) {
-               DEBUG(0, ("Unable to obtain sys module while printing error"));
-               return;
-       }
-
-       old_stderr = PyObject_GetAttrString(sys_module, "stderr");
-       if (old_stderr == NULL) {
-               DEBUG(0, ("Unable to obtain old stderr"));
-               Py_DECREF(sys_module);
-               return;
-       }
-
-       new_stderr = Py_ErrorHttpStream();
-       if (new_stderr == NULL) {
-               DEBUG(0, ("Unable to create error stream"));
-               Py_DECREF(sys_module);
-               Py_DECREF(old_stderr);
-               return;
-       }
-
-       PyObject_SetAttrString(sys_module, "stderr", new_stderr);
-       Py_DECREF(new_stderr);
-
-       PyErr_Restore(ptype, pvalue, ptb);
-       PyErr_Print();
-
-       PyObject_SetAttrString(sys_module, "stderr", old_stderr);
-       Py_DECREF(old_stderr);
-
-       Py_DECREF(sys_module);
-}
-
-static PyObject *create_environ(bool tls, int content_length, struct http_header *headers, const char *request_method, const char *servername, int serverport, PyObject *inputstream, const char *request_string)
-{
-       PyObject *env;
-       PyObject *py_scheme;
-       PyObject *py_val;
-       struct http_header *hdr;
-       char *questionmark;
-
-       env = PyDict_New();
-       if (env == NULL) {
-               return NULL;
-       }
-
-       PyDict_SetItemString(env, "wsgi.input", inputstream);
-
-       py_val = Py_ErrorHttpStream();
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "wsgi.errors", py_val);
-       Py_DECREF(py_val);
-
-       py_val = Py_BuildValue("(i,i)", 1, 0);
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "wsgi.version", py_val);
-       Py_DECREF(py_val);
-       PyDict_SetItemString(env, "wsgi.multithread", Py_False);
-       PyDict_SetItemString(env, "wsgi.multiprocess", Py_False);
-       PyDict_SetItemString(env, "wsgi.run_once", Py_False);
-       py_val = PyStr_FromString("HTTP/1.0");
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "SERVER_PROTOCOL", py_val);
-       Py_DECREF(py_val);
-       if (content_length > 0) {
-               py_val = PyLong_FromLong(content_length);
-               if (py_val == NULL) goto error;
-               PyDict_SetItemString(env, "CONTENT_LENGTH", py_val);
-               Py_DECREF(py_val);
-       }
-       py_val = PyStr_FromString(request_method);
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "REQUEST_METHOD", py_val);
-       Py_DECREF(py_val);
-
-       /* There is always a single wsgi app to which all requests are redirected,
-        * so SCRIPT_NAME will be / */
-       py_val = PyStr_FromString("/");
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "SCRIPT_NAME", py_val);
-       Py_DECREF(py_val);
-       questionmark = strchr(request_string, '?');
-       if (questionmark == NULL) {
-               py_val = PyStr_FromString(request_string);
-               if (py_val == NULL) goto error;
-               PyDict_SetItemString(env, "PATH_INFO", py_val);
-               Py_DECREF(py_val);
-       } else {
-               py_val = PyStr_FromString(questionmark+1);
-               if (py_val == NULL) goto error;
-               PyDict_SetItemString(env, "QUERY_STRING", py_val);
-               Py_DECREF(py_val);
-               py_val = PyStr_FromStringAndSize(request_string, questionmark-request_string);
-               if (py_val == NULL) goto error;
-               PyDict_SetItemString(env, "PATH_INFO", py_val);
-               Py_DECREF(py_val);
-       }
-
-       py_val = PyStr_FromString(servername);
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "SERVER_NAME", py_val);
-       Py_DECREF(py_val);
-       py_val = PyStr_FromFormat("%d", serverport);
-       if (py_val == NULL) goto error;
-       PyDict_SetItemString(env, "SERVER_PORT", py_val);
-       Py_DECREF(py_val);
-
-       for (hdr = headers; hdr; hdr = hdr->next) {
-               char *name;
-               if (!strcasecmp(hdr->name, "Content-Type")) {
-                       py_val = PyStr_FromString(hdr->value);
-                       PyDict_SetItemString(env, "CONTENT_TYPE", py_val);
-                       Py_DECREF(py_val);
-               } else {
-                       if (asprintf(&name, "HTTP_%s", hdr->name) < 0) {
-                               PyErr_NoMemory();
-                               goto error;
-                       }
-                       py_val = PyStr_FromString(hdr->value);
-                       PyDict_SetItemString(env, name, py_val);
-                       Py_DECREF(py_val);
-                       free(name);
-               }
-       }
-
-       if (tls) {
-               py_scheme = PyStr_FromString("https");
-       } else {
-               py_scheme = PyStr_FromString("http");
-       }
-       if (py_scheme == NULL) goto error;
-       PyDict_SetItemString(env, "wsgi.url_scheme", py_scheme);
-       Py_DECREF(py_scheme);
-
-       return env;
-error:
-       Py_DECREF(env);
-       return NULL;
-}
-
-static void wsgi_serve_500(struct websrv_context *web)
-{
-       struct http_header *headers = NULL;
-       const char *contents[] = {
-               "An internal server error occurred while handling this request. ",
-               "Please refer to the server logs for more details. ",
-               NULL
-       };
-       int i;
-
-       websrv_output_headers(web, "500 Internal Server Error", headers);
-       for (i = 0; contents[i]; i++) {
-               websrv_output(web, contents[i], strlen(contents[i]));
-       }
-}
-
-static void wsgi_process_http_input(struct web_server_data *wdata,
-                                   struct websrv_context *web)
-{
-       PyObject *py_environ, *result, *item, *iter;
-       PyObject *request_handler = (PyObject *)wdata->private_data;
-       struct tsocket_address *my_address = web->conn->local_address;
-       const char *addr = "0.0.0.0";
-       uint16_t port = 0;
-       web_request_Object *py_web;
-       PyObject *py_input_stream;
-
-       py_web = PyObject_New(web_request_Object, &web_request_Type);
-       if (py_web == NULL) {
-               DEBUG_Print_PyError(0, "Unable to allocate web request");
-               return;
-       }
-       py_web->web = web;
-
-       if (tsocket_address_is_inet(my_address, "ip")) {
-               addr = tsocket_address_inet_addr_string(my_address, wdata);
-               port = tsocket_address_inet_port(my_address);
-       }
-
-       py_input_stream = Py_InputHttpStream(web);
-       if (py_input_stream == NULL) {
-               DEBUG_Print_PyError(0, "unable to create python input stream");
-               return;
-       }
-
-       py_environ = create_environ(tls_enabled(web->conn->socket),
-                                   web->input.content_length, 
-                                   web->input.headers, 
-                                   web->input.post_request?"POST":"GET",
-                                   addr,
-                                   port,
-                                   py_input_stream,
-                                   web->input.url
-                                   );
-
-       Py_DECREF(py_input_stream);
-
-       if (py_environ == NULL) {
-               DEBUG_Print_PyError(0, "Unable to create WSGI environment object");
-               wsgi_serve_500(web);
-               return;
-       }
-
-       result = PyObject_CallMethod(request_handler, discard_const_p(char, "__call__"), discard_const_p(char, "OO"),
-                                      py_environ, PyObject_GetAttrString((PyObject *)py_web, "start_response"));
-
-       if (result == NULL) {
-               DEBUG_Print_PyError(0, "error while handling request");
-               wsgi_serve_500(web);
-               return;
-       }
-
-       iter = PyObject_GetIter(result);
-       Py_DECREF(result);
-
-       if (iter == NULL) {
-               DEBUG_Print_PyError(0, "application did not return iterable");
-               wsgi_serve_500(web);
-               return;
-       }
-
-       /* Now, iter over all the data returned */
-
-       while ((item = PyIter_Next(iter))) {
-               Py_ssize_t size = 0;
-               char *value = NULL;
-               int ret = PyBytes_AsStringAndSize(item, &value, &size);
-               if (ret == -1) {
-                       DEBUG_Print_PyError(0, "application failed to "
-                               "extract string from iterable");
-                       wsgi_serve_500(web);
-                       return;
-               }
-               websrv_output(web, value, size);
-               Py_DECREF(item);
-       }
-
-       Py_DECREF(iter);
-}
-
-bool wsgi_initialize(struct web_server_data *wdata)
-{
-       PyObject *py_web_server;
-
-       Py_Initialize();
-
-       py_update_path(); /* Ensure that we have the Samba paths at
-                          * the start of the sys.path() */
-
-       if (PyType_Ready(&web_request_Type) < 0)
-               return false;
-
-       if (PyType_Ready(&input_Stream_Type) < 0)
-               return false;
-
-       if (PyType_Ready(&error_Stream_Type) < 0)
-               return false;
-
-       wdata->http_process_input = wsgi_process_http_input;
-       py_web_server = PyImport_ImportModule("samba.web_server");
-       if (py_web_server == NULL) {
-               DEBUG_Print_PyError(0, "Unable to find web server");
-               return false;
-       }
-       wdata->private_data = py_web_server;
-       return true;
-}
index a72094838d435847cd759a370b3de739d69324fc..b07ae1b5df2d0e77d42a8696ad578166f6683732 100644 (file)
@@ -89,7 +89,6 @@ bld.RECURSE('source4/echo_server')
 bld.RECURSE('source4/smb_server')
 bld.RECURSE('source4/rpc_server')
 bld.RECURSE('source4/ldap_server')
-bld.RECURSE('source4/web_server')
 bld.RECURSE('source4/winbind')
 bld.RECURSE('source4/nbt_server')
 bld.RECURSE('source4/wrepl_server')