src/server/daemon/protocol.c

changeset 14
b8bf95b39952
parent 11
24d804a2799f
child 21
627b09ee74e4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/daemon/protocol.c	Sat Jan 14 13:53:44 2012 +0100
@@ -0,0 +1,315 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "protocol.h"
+
+#include "../util/pblock.h"
+#include "../util/pool.h"
+#include "session.h"
+#include "../util/io.h"
+
+#include "../util/strbuf.h"
+
+
+void protocol_status(Session *sn, Request *rq, int n, const char *m) {
+    rq->status_num = n;
+
+    const char *msg = m ? m : protocol_status_message(n);
+
+    pb_param *pp = pblock_removekey(pb_key_status, rq->srvhdrs);
+    if (pp != NULL) {
+        param_free(pp);
+    }
+
+    pp = pblock_key_param_create(rq->srvhdrs, pb_key_status, msg, strlen(msg));
+    pblock_kpinsert(pb_key_status, pp, rq->srvhdrs);
+}
+
+
+/*
+ * http_status_message from Open Webserver (frame/http.cpp)
+ * TODO: replace, use sstr_t
+ */
+NSAPI_PUBLIC const char * protocol_status_message (int code)
+{
+    const char *r;
+
+    switch (code)
+    {
+        case PROTOCOL_CONTINUE : // 100
+            r = "Continue";
+            break;
+        case PROTOCOL_SWITCHING: //101
+            r = "Switching Protocols";
+            break;
+        case PROTOCOL_OK: // 200
+            r = "OK";
+            break;
+        case PROTOCOL_CREATED: // 201
+            r = "Created";
+            break;
+        case PROTOCOL_ACCEPTED: // 202
+            r = "Accepted";
+            break;
+        case PROTOCOL_NONAUTHORITATIVE: // 203
+            r = "Non-Authoritative Information";
+            break;
+        case PROTOCOL_NO_CONTENT: //204
+        /* There is another define to PROTOCOL_NO_RESPONSE for 204 in nsapi.h
+           The spec maps this to No Content.
+           Hence cahnging this to No Content
+        */
+            r = "No Content";
+            break;
+        case PROTOCOL_RESET_CONTENT: // 205
+            r = "Reset Content";
+            break;
+        case PROTOCOL_PARTIAL_CONTENT: // 206
+            r = "Partial Content";
+            break;
+        case PROTOCOL_MULTI_STATUS: // 207
+            r = "Multi Status";
+            break;
+        case PROTOCOL_MULTIPLE_CHOICES: // 300
+            r = "Multiple Choices";
+            break;
+        case PROTOCOL_MOVED_PERMANENTLY: // 301
+            r = "Moved Permanently";
+            break;
+        case PROTOCOL_REDIRECT:          // 302
+            r = "Moved Temporarily"; /* The spec actually says "Found" */
+            break;
+        case PROTOCOL_SEE_OTHER:         // 303
+            r = "See Other";
+            break;
+        case PROTOCOL_NOT_MODIFIED:      // 304
+            r = "Use local copy";    /* The spec actually says "Not Modified" */
+            break;
+        case PROTOCOL_USE_PROXY:         // 305
+            r = "Use Proxy";
+            break;
+        case PROTOCOL_TEMPORARY_REDIRECT: // 307
+            r = "Temporary Redirect";
+            break;
+        case PROTOCOL_BAD_REQUEST:        // 400
+            r = "Bad request";
+            break;
+        case PROTOCOL_UNAUTHORIZED:       // 401
+            r = "Unauthorized";
+            break;
+        case PROTOCOL_PAYMENT_REQUIRED:   // 402
+            r = "Payment Required";
+            break;
+        case PROTOCOL_FORBIDDEN:          // 403
+            r = "Forbidden";
+            break;
+        case PROTOCOL_NOT_FOUND:         // 404
+            r = "Not found";
+            break;
+        case PROTOCOL_METHOD_NOT_ALLOWED: // 405                /* HTTP/1.1 */
+            r = "Method Not Allowed";
+            break;
+        case PROTOCOL_NOT_ACCEPTABLE: // 406                /* HTTP/1.1 */
+            r = "Not Acceptable";
+            break;
+        case PROTOCOL_PROXY_UNAUTHORIZED: // 407
+            r = "Proxy Authentication Required";
+            break;
+        case PROTOCOL_REQUEST_TIMEOUT:    // 408            /* HTTP/1.1 */
+            r = "Request Timeout";
+            break;
+        case PROTOCOL_CONFLICT:           // 409
+            r = "Conflict";                         /* HTTP/1.1 */
+            break;
+        case PROTOCOL_GONE:           // 410
+            r = "Gone";                         /* HTTP/1.1 */
+            break;
+        case PROTOCOL_LENGTH_REQUIRED:    // 411                /* HTTP/1.1 */
+            r = "Length Required";
+            break;
+        case PROTOCOL_PRECONDITION_FAIL:  // 412                /* HTTP/1.1 */
+            r = "Precondition Failed";
+            break;
+        case PROTOCOL_ENTITY_TOO_LARGE:   // 413                /* HTTP/1.1 */
+            r = "Request Entity Too Large";
+            break;
+        case PROTOCOL_URI_TOO_LARGE:      // 414                /* HTTP/1.1 */
+            r = "Request-URI Too Large";
+            break;
+        case PROTOCOL_UNSUPPORTED_MEDIA_TYPE: // 415
+            r = "Unsupported Media Type";
+            break;
+        case PROTOCOL_REQUESTED_RANGE_NOT_SATISFIABLE: // 416
+            r = "Requested range not satisfiable";
+            break;
+        case PROTOCOL_EXPECTATION_FAILED:     // 417
+            r = "Expectation Failed";
+            break;
+        case PROTOCOL_LOCKED:     // 423
+            r = "Locked";
+            break;
+        case PROTOCOL_FAILED_DEPENDENCY:     // 424
+            r = "Failed Dependency";
+            break;
+        case PROTOCOL_SERVER_ERROR:           // 500
+            r = "Server Error";           /* The spec actually says "Internal Server Error" */
+            break;
+        case PROTOCOL_NOT_IMPLEMENTED:        // 501
+            r = "Not Implemented";
+            break;
+        case PROTOCOL_BAD_GATEWAY:            // 502
+            r = "Bad Gateway";
+            break;
+        case PROTOCOL_SERVICE_UNAVAILABLE:    // 503
+            r = "Service Unavailable";
+            break;
+        case PROTOCOL_GATEWAY_TIMEOUT:        // 504            /* HTTP/1.1 */
+            r = "Gateway Timeout";
+            break;
+        case PROTOCOL_VERSION_NOT_SUPPORTED:  // 505            /* HTTP/1.1 */
+            r = "HTTP Version Not Supported";
+            break;
+        case PROTOCOL_INSUFFICIENT_STORAGE:  // 507
+            r = "Insufficient Storage";
+            break;
+        default:
+            switch (code / 100)
+            {
+                case 1:
+                    r = "Information";
+                    break;
+                case 2:
+                    r = "Success";
+                    break;
+                case 3:
+                    r = "Redirect";
+                    break;
+                case 4:
+                    r = "Client error";
+                    break;
+                case 5:
+                    r = "Server error";
+                    break;
+                default:
+                    r = "Unknown reason";
+                    break;
+            }
+            break;
+    }
+
+    return r;
+}
+
+
+void add_http_status_line(sbuf_t *out, pool_handle_t *pool, Request *rq) {
+    sbuf_write(out, "HTTP/1.1 ", 9);
+
+    char *status_code_str = pool_malloc(pool, 8);
+    int sc_len = snprintf(status_code_str, 8, "%d ", rq->status_num);
+    sbuf_write(out, status_code_str, sc_len);
+    
+    char *scmsg = pblock_findkeyval(pb_key_status, rq->srvhdrs);
+    sbuf_write(out, scmsg, strlen(scmsg));
+
+    sbuf_write(out, "\r\n", 2);
+}
+
+void add_http_response_header(sbuf_t *out, Request *rq) {
+    pblock   *h = rq->srvhdrs;
+    pb_entry *p;
+
+    for(int i=0;i<h->hsize;i++) {
+        p = h->ht[i];
+        while(p != NULL) {
+            /* from http.cpp */
+            const pb_key *key = PARAM_KEY(p->param);
+            if (key == pb_key_status || key == pb_key_server || key == pb_key_date) {
+                /* Skip internal Status:, Server:, and Date: information */
+                p = p->next;
+                continue;
+            }
+            /* end http.cpp */
+
+            char *name  = p->param->name;
+            char *value = p->param->value;
+
+            /* make first char of name uppercase */
+            if(name[0] > 90) {
+                name[0] -= 32;
+            }
+
+            sbuf_write(out, name, strlen(name));
+            sbuf_write(out, ": ", 2);
+            sbuf_write(out, value, strlen(value));
+            sbuf_write(out, "\r\n", 2);
+
+            p = p->next;
+        }
+    }
+}
+
+int http_start_response(Session *sn, Request *rq) {
+    int fd = ((SystemIOStream*)sn->csd)->fd;
+
+    /* set socket blocking */
+    int flags;
+    flags = fcntl(fd, F_GETFL, 0);
+    fcntl(fd, F_SETFL, flags ^ O_NONBLOCK);
+
+    /* iovec output buffer */
+    sbuf_t *out = sbuf_new(512);
+
+    /* add the http status line to the output buffer */
+    add_http_status_line(out, sn->pool, rq);
+
+    /* add server header */
+    sbuf_write(out, "Server: WS uap-dev\r\n", 20);
+
+    /* add header from rq->srvhdrs */
+    add_http_response_header(out, rq);
+
+    /* response header end */
+    sbuf_write(out, "\r\n", 2);
+
+    /* flush buffer to the socket */
+    write(fd, out->ptr, out->length);
+    sbuf_free(out);
+    
+    rq->senthdrs = 1;
+}
+
+int request_header(char *name, char **value, Session *sn, Request *rq) {
+    const pb_key *key = pblock_key(name);
+    pb_param *pp = pblock_findkey(key, rq->headers);
+    if(pp != NULL) {
+        value = &pp->value;
+        return REQ_PROCEED;
+    } else {
+        return REQ_ABORTED;
+    }
+}

mercurial