I wrote a patch to add OPTIONS as a supported HTTP method in Polipo. This
arose out of the new use for the OPTIONS method for preflighted requests
in HTTP access control (CORS), which is used when a XMLHttpRequest call
across domain boundaries in reasonably current browsers (Chrome 4+,
Firefox 3.5+, IE 10+) utilizes either

* a HTTP method other than GET, HEAD or POST
* a content type other than plain text or form data
* a custom request header.

In my example, this occurs because a script on www.domain.com tries to
query a JSON file on api.domain.com, which fails with a 501 at the moment
when the page is requested via HTTP (obviously, it works over the tunneled
connection when requested via HTTPS).

See also:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

As per the spec (RFC 7231, section 4.3.7), responses to the OPTIONS method
are not cacheable, so I added OPTIONS as an equal alternative to POST and
PUT requests (especially since OPTIONS allows for an optional request body
as well, although this is unheard of in the wild).

This patch also could be easily extended to support the DELETE method
used by some RESTful web services.
https://github.com/jech/polipo/issues/26

---
 client.c     |  5 +++--
 http.h       |  1 +
 http_parse.c |  2 ++
 polipo.texi  | 10 +++++-----
 server.c     |  4 +++-
 5 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/client.c b/client.c
index 58bb608..acb08f2 100644
--- a/client.c
+++ b/client.c
@@ -739,7 +739,7 @@ httpClientRequest(HTTPRequestPtr request, AtomPtr url)

     if(body_len < 0) {
         if(request->method == METHOD_GET || request->method == METHOD_HEAD ||
-           request->method == METHOD_POST)
+           request->method == METHOD_POST || request->method == METHOD_OPTIONS)
             body_len = 0;
     }
     connection->bodylen = body_len;
@@ -868,7 +868,8 @@ httpClientRequestContinue(int forbidden_code, AtomPtr url,
         httpLocalRequest :
         httpServerRequest;

-    if(request->method == METHOD_POST || request->method == METHOD_PUT) {
+    if(request->method == METHOD_POST || request->method == METHOD_PUT
+       || request->method == METHOD_OPTIONS) {
         do {
             object = findObject(OBJECT_HTTP, url->string, url->length);
             if(object) {
diff --git a/http.h b/http.h
index 2a06a5a..3771421 100644
--- a/http.h
+++ b/http.h
@@ -105,6 +105,7 @@ typedef struct _HTTPConnection {
 #define METHOD_CONNECT 3
 #define METHOD_POST 4
 #define METHOD_PUT 5
+#define METHOD_OPTIONS 6

 #define REQUEST_SIDE(request) ((request)->method >= METHOD_POST)

diff --git a/http_parse.c b/http_parse.c
index a5940ff..20f376a 100644
--- a/http_parse.c
+++ b/http_parse.c
@@ -417,6 +417,8 @@ httpParseClientFirstLine(const char *restrict buf,
int offset,
         method = METHOD_PUT;
     else if(y == x + 7 && memcmp(buf + x, "CONNECT", 7) == 0)
         method = METHOD_CONNECT;
+    else if(y == x + 7 && memcmp(buf + x, "OPTIONS", 7) == 0)
+        method = METHOD_OPTIONS;
     else
         method = METHOD_UNKNOWN;

diff --git a/polipo.texi b/polipo.texi
index 3f3adf4..1a1b0e5 100644
--- a/polipo.texi
+++ b/polipo.texi
@@ -305,10 +305,10 @@
 resource with a different instance; it is typically used by web
 publishing applications.

-@samp{POST} and @samp{PUT} requests are handled by Polipo pretty much
-like @samp{GET} and @samp{HEAD}; however, for various reasons, some
-precautions must be taken.  In particular, any cached data for the
-resource they refer to must be discarded, and they can never be
+@samp{POST}, @samp{PUT} and @samp{OPTIONS} requests are handled by
+Polipo pretty much like @samp{GET} and @samp{HEAD}; however, for various
+reasons, some precautions must be taken.  In particular, any cached data
+for the resource they refer to must be discarded, and they can never be
 pipelined.

 Finally, HTTP/1.1 includes a convenient backdoor with the
@@ -316,7 +316,7 @@
 @ref{Tunnelling connections}.

 Polipo does not currently handle the more exotic methods such as
-@samp{OPTIONS} and @samp{PROPFIND}.
+@samp{PROPFIND}.

 @node Running, Network, Background, Top
 @chapter Running Polipo
diff --git a/server.c b/server.c
index e445d53..3e697a1 100644
--- a/server.c
+++ b/server.c
@@ -467,7 +467,8 @@ httpMakeServerRequest(char *name, int port,
ObjectPtr object,
             return 1;
         }
     } else if(expectContinue >= 2 && server->version == HTTP_11) {
-        if(request->method == METHOD_POST || request->method == METHOD_PUT)
+        if(request->method == METHOD_POST || request->method == METHOD_PUT
+           || request->method == METHOD_OPTIONS)
             request->flags |= REQUEST_WAIT_CONTINUE;
     }

@@ -1593,6 +1594,7 @@ httpWriteRequest(HTTPConnectionPtr connection,
HTTPRequestPtr request,
     case METHOD_HEAD: m = "HEAD"; break;
     case METHOD_POST: m = "POST"; break;
     case METHOD_PUT: m = "PUT"; break;
+    case METHOD_OPTIONS: m = "OPTIONS"; break;
     default: abort();
     }
     n = snnprintf(connection->reqbuf, n, bufsize, "%s ", m);

------------------------------------------------------------------------------
_______________________________________________
Polipo-users mailing list
Polipo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/polipo-users

Reply via email to