+++ /dev/null
-# -*- 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()
+++ /dev/null
-/*
- 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);
-}
+++ /dev/null
-/*
- 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__ */
+++ /dev/null
-#!/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()
- )
+++ /dev/null
-/*
- 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;
-}
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')