Repository: trafficserver Updated Branches: refs/heads/master 7b1b93180 -> 4b2429b60
TS-2972 Fix indentation as per our coding standards Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/4b2429b6 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/4b2429b6 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/4b2429b6 Branch: refs/heads/master Commit: 4b2429b60b65cbe13dc59fe7fb9c8e12a436af84 Parents: 7b1b931 Author: Leif Hedstrom <[email protected]> Authored: Wed Jul 30 11:17:50 2014 -0600 Committer: Leif Hedstrom <[email protected]> Committed: Thu Jul 31 10:25:21 2014 -0600 ---------------------------------------------------------------------- plugins/experimental/authproxy/authproxy.cc | 1187 +++++++++++----------- plugins/experimental/authproxy/utils.cc | 253 +++-- plugins/experimental/authproxy/utils.h | 98 +- 3 files changed, 747 insertions(+), 791 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4b2429b6/plugins/experimental/authproxy/authproxy.cc ---------------------------------------------------------------------- diff --git a/plugins/experimental/authproxy/authproxy.cc b/plugins/experimental/authproxy/authproxy.cc index cba2554..fd6c112 100644 --- a/plugins/experimental/authproxy/authproxy.cc +++ b/plugins/experimental/authproxy/authproxy.cc @@ -27,7 +27,7 @@ #include "utils.h" #include <string> -#include <memory> // placement new +#include <memory> // placement new #include <limits> #include <cstring> #include <cstdlib> @@ -43,651 +43,626 @@ using std::strlen; struct AuthRequestContext; -typedef bool (*AuthRequestTransform)(AuthRequestContext * auth, const sockaddr * saddr); +typedef bool(*AuthRequestTransform) (AuthRequestContext* auth, const sockaddr* saddr); // We can operate in global plugin mode or remap plugin mode. If we are in // global mode, then we will authorize every request. In remap mode, we will // only authorize tagged requests. -static bool AuthTaggedRequestOnly = false; -static int AuthTaggedRequestArg = -1; +static bool AuthTaggedRequestOnly = false; +static int AuthTaggedRequestArg = -1; -static TSCont AuthOsDnsContinuation; +static TSCont AuthOsDnsContinuation; struct AuthOptions { - char * hostname; - int hostport; - bool force; - AuthRequestTransform transform; + char* hostname; + int hostport; + bool force; + AuthRequestTransform transform; - AuthOptions() : hostname(NULL), hostport(8080), force(false), transform(NULL) { - } + AuthOptions(): + hostname(NULL), hostport(8080), force(false), transform(NULL) + { } - ~AuthOptions() { - TSfree(hostname); - } + ~AuthOptions() + { + TSfree(hostname); + } }; // Global options; used when we are in global authorization mode. -static AuthOptions * AuthGlobalOptions; +static AuthOptions* AuthGlobalOptions; // Generic state handler callback. This should handle the event, and return a // new event. The return value controls the subsequent state transition: // TS_EVENT_CONTINUE Continue the state machine, returning to the ATS event loop // TS_EVENT_NONE Stop processing (because a nested dispatch occurred) // Anything else Continue the state machine with this event -typedef TSEvent (*StateHandler)(struct AuthRequestContext *, void * edata); +typedef TSEvent (*StateHandler) (struct AuthRequestContext*, void* edata); -struct StateTransition { - TSEvent event; - StateHandler handler; - const StateTransition * next; +struct StateTransition +{ + TSEvent event; + StateHandler handler; + const StateTransition* next; }; -static TSEvent StateAuthProxyConnect(AuthRequestContext *, void *); -static TSEvent StateAuthProxyResolve(AuthRequestContext *, void *); -static TSEvent StateAuthProxyWriteComplete(AuthRequestContext *, void *); -static TSEvent StateUnauthorized(AuthRequestContext *, void *); -static TSEvent StateAuthorized(AuthRequestContext *, void *); +static TSEvent StateAuthProxyConnect(AuthRequestContext*, void*); +static TSEvent StateAuthProxyResolve(AuthRequestContext*, void*); +static TSEvent StateAuthProxyWriteComplete(AuthRequestContext*, void*); +static TSEvent StateUnauthorized(AuthRequestContext*, void*); +static TSEvent StateAuthorized(AuthRequestContext*, void*); -static TSEvent StateAuthProxyReadHeaders(AuthRequestContext *, void *); -static TSEvent StateAuthProxyCompleteHeaders(AuthRequestContext *, void *); -static TSEvent StateAuthProxyReadContent(AuthRequestContext *, void *); -static TSEvent StateAuthProxyCompleteContent(AuthRequestContext *, void *); +static TSEvent StateAuthProxyReadHeaders(AuthRequestContext*, void*); +static TSEvent StateAuthProxyCompleteHeaders(AuthRequestContext*, void*); +static TSEvent StateAuthProxyReadContent(AuthRequestContext*, void*); +static TSEvent StateAuthProxyCompleteContent(AuthRequestContext*, void*); -static TSEvent StateAuthProxySendResponse(AuthRequestContext *, void *); +static TSEvent StateAuthProxySendResponse(AuthRequestContext*, void*); // Trampoline state that just returns TS_EVENT_CONTINUE. We need this to be // able to transition between state tables when we are in a loop. -static TSEvent StateContinue(AuthRequestContext *, void *) +static TSEvent +StateContinue(AuthRequestContext*, void*) { - return TS_EVENT_CONTINUE; + return TS_EVENT_CONTINUE; } // State table for sending the auth proxy response to the client. -static const StateTransition StateTableSendResponse[] = -{ - { TS_EVENT_HTTP_SEND_RESPONSE_HDR, StateAuthProxySendResponse, NULL }, - { TS_EVENT_NONE, NULL, NULL } +static const StateTransition StateTableSendResponse[] = { + { TS_EVENT_HTTP_SEND_RESPONSE_HDR, StateAuthProxySendResponse, NULL }, + { TS_EVENT_NONE, NULL, NULL } }; // State table for reading the proxy response body content. -static const StateTransition StateTableProxyReadContent[] = -{ - { TS_EVENT_VCONN_READ_READY, StateAuthProxyReadContent, StateTableProxyReadContent }, - { TS_EVENT_VCONN_READ_COMPLETE, StateAuthProxyReadContent, StateTableProxyReadContent }, - { TS_EVENT_VCONN_EOS, StateAuthProxyCompleteContent, StateTableProxyReadContent }, - { TS_EVENT_HTTP_SEND_RESPONSE_HDR, StateContinue, StateTableSendResponse }, - { TS_EVENT_ERROR, StateUnauthorized, NULL }, - { TS_EVENT_IMMEDIATE, StateAuthorized, NULL }, - { TS_EVENT_NONE, NULL, NULL } +static const StateTransition StateTableProxyReadContent[] = { + { TS_EVENT_VCONN_READ_READY, StateAuthProxyReadContent, StateTableProxyReadContent }, + { TS_EVENT_VCONN_READ_COMPLETE, StateAuthProxyReadContent, StateTableProxyReadContent }, + { TS_EVENT_VCONN_EOS, StateAuthProxyCompleteContent, StateTableProxyReadContent }, + { TS_EVENT_HTTP_SEND_RESPONSE_HDR, StateContinue, StateTableSendResponse }, + { TS_EVENT_ERROR, StateUnauthorized, NULL }, + { TS_EVENT_IMMEDIATE, StateAuthorized, NULL }, + { TS_EVENT_NONE, NULL, NULL } }; // State table for reading the auth proxy response header. -static const StateTransition StateTableProxyReadHeader[] = -{ - { TS_EVENT_VCONN_READ_READY, StateAuthProxyReadHeaders, StateTableProxyReadHeader }, - { TS_EVENT_VCONN_READ_COMPLETE, StateAuthProxyReadHeaders, StateTableProxyReadHeader }, - { TS_EVENT_HTTP_READ_REQUEST_HDR, StateAuthProxyCompleteHeaders, StateTableProxyReadHeader }, - { TS_EVENT_HTTP_SEND_RESPONSE_HDR, StateContinue, StateTableSendResponse }, - { TS_EVENT_HTTP_CONTINUE, StateAuthProxyReadContent, StateTableProxyReadContent }, - { TS_EVENT_VCONN_EOS, StateUnauthorized, NULL }, // XXX Should we check headers on EOS? - { TS_EVENT_ERROR, StateUnauthorized, NULL }, - { TS_EVENT_IMMEDIATE, StateAuthorized, NULL }, - { TS_EVENT_NONE, NULL, NULL } +static const StateTransition StateTableProxyReadHeader[] = { + { TS_EVENT_VCONN_READ_READY, StateAuthProxyReadHeaders, StateTableProxyReadHeader }, + { TS_EVENT_VCONN_READ_COMPLETE, StateAuthProxyReadHeaders, StateTableProxyReadHeader }, + { TS_EVENT_HTTP_READ_REQUEST_HDR, StateAuthProxyCompleteHeaders, StateTableProxyReadHeader }, + { TS_EVENT_HTTP_SEND_RESPONSE_HDR, StateContinue, StateTableSendResponse }, + { TS_EVENT_HTTP_CONTINUE, StateAuthProxyReadContent, StateTableProxyReadContent }, + { TS_EVENT_VCONN_EOS, StateUnauthorized, NULL }, // XXX Should we check headers on EOS? + { TS_EVENT_ERROR, StateUnauthorized, NULL }, + { TS_EVENT_IMMEDIATE, StateAuthorized, NULL }, + { TS_EVENT_NONE, NULL, NULL } }; // State table for sending the request to the auth proxy. -static const StateTransition StateTableProxyRequest[] = -{ - { TS_EVENT_HOST_LOOKUP, StateAuthProxyConnect, StateTableProxyRequest }, - { TS_EVENT_VCONN_WRITE_COMPLETE, StateAuthProxyWriteComplete, StateTableProxyReadHeader }, - { TS_EVENT_ERROR, StateUnauthorized, NULL }, - { TS_EVENT_NONE, NULL, NULL } +static const StateTransition StateTableProxyRequest[] = { + { TS_EVENT_HOST_LOOKUP, StateAuthProxyConnect, StateTableProxyRequest}, + { TS_EVENT_VCONN_WRITE_COMPLETE, StateAuthProxyWriteComplete, StateTableProxyReadHeader }, + { TS_EVENT_ERROR, StateUnauthorized, NULL }, + { TS_EVENT_NONE, NULL, NULL } }; // Initial state table. -static const StateTransition StateTableInit[] = -{ - { TS_EVENT_HTTP_OS_DNS, StateAuthProxyResolve, StateTableProxyRequest }, - { TS_EVENT_ERROR, StateUnauthorized, NULL }, - { TS_EVENT_NONE, NULL, NULL } +static const StateTransition StateTableInit[] = { + { TS_EVENT_HTTP_OS_DNS, StateAuthProxyResolve, StateTableProxyRequest }, + { TS_EVENT_ERROR, StateUnauthorized, NULL }, + { TS_EVENT_NONE, NULL, NULL } }; struct AuthRequestContext { - TSHttpTxn txn; // Original client transaction we are authorizing. - TSCont cont; // Continuation for this state machine. - TSVConn vconn; // Virtual connection to the auth proxy. - TSHttpParser hparser;// HTTP response header parser. - HttpHeader rheader;// HTTP response header. - HttpIoBuffer iobuf; - bool is_head;// This is a HEAD request - bool read_body; - - const StateTransition * state; - - AuthRequestContext() - : txn(NULL), cont(NULL), vconn(NULL), hparser(TSHttpParserCreate()), - rheader(), iobuf(TS_IOBUFFER_SIZE_INDEX_4K), is_head(false), read_body(true), state(NULL) { - this->cont = TSContCreate(dispatch, TSMutexCreate()); - TSContDataSet(this->cont, this); + TSHttpTxn txn; // Original client transaction we are authorizing. + TSCont cont; // Continuation for this state machine. + TSVConn vconn; // Virtual connection to the auth proxy. + TSHttpParser hparser; // HTTP response header parser. + HttpHeader rheader; // HTTP response header. + HttpIoBuffer iobuf; + bool is_head; // This is a HEAD request + bool read_body; + + const StateTransition* state; + + AuthRequestContext() + : txn(NULL), cont(NULL), vconn(NULL), hparser(TSHttpParserCreate()), rheader(), + iobuf(TS_IOBUFFER_SIZE_INDEX_4K), is_head(false), read_body(true), state(NULL) + { + this->cont = TSContCreate(dispatch, TSMutexCreate()); + TSContDataSet(this->cont, this); + } + + ~AuthRequestContext() + { + TSContDataSet(this->cont, NULL); + TSContDestroy(this->cont); + TSHttpParserDestroy(this->hparser); + if (this->vconn) { + TSVConnClose(this->vconn); } + } - ~AuthRequestContext() { - TSContDataSet(this->cont, NULL); - TSContDestroy(this->cont); - TSHttpParserDestroy(this->hparser); - if (this->vconn) { - TSVConnClose(this->vconn); - } - } + const AuthOptions* + options() const + { + AuthOptions* opt; - const AuthOptions * options() const { - AuthOptions * opt; + opt = (AuthOptions*) TSHttpTxnArgGet(this->txn, AuthTaggedRequestArg); + return opt ? opt : AuthGlobalOptions; + } - opt = (AuthOptions *)TSHttpTxnArgGet(this->txn, AuthTaggedRequestArg); - return opt ? opt : AuthGlobalOptions; - } - - static AuthRequestContext * allocate(); - static void destroy(AuthRequestContext *); - static int dispatch(TSCont, TSEvent, void *); + static AuthRequestContext* allocate(); + static void destroy(AuthRequestContext*); + static int dispatch(TSCont, TSEvent, void*); }; -AuthRequestContext * +AuthRequestContext* AuthRequestContext::allocate() { - void * ptr = TSmalloc(sizeof(AuthRequestContext)); - return new(ptr) AuthRequestContext(); + void* ptr = TSmalloc(sizeof(AuthRequestContext)); + return new(ptr) AuthRequestContext(); } void -AuthRequestContext::destroy(AuthRequestContext * auth) +AuthRequestContext::destroy(AuthRequestContext* auth) { - if (auth) { - auth->~AuthRequestContext(); - TSfree(auth); - } + if (auth) { + auth->~AuthRequestContext(); + TSfree(auth); + } } int -AuthRequestContext::dispatch(TSCont cont, TSEvent event, void * edata) +AuthRequestContext::dispatch(TSCont cont, TSEvent event, void* edata) { - AuthRequestContext * auth = (AuthRequestContext *)TSContDataGet(cont); - const StateTransition * s; + AuthRequestContext* auth = (AuthRequestContext*)TSContDataGet(cont); + const StateTransition* s; pump: - for (s = auth->state; s && s->event; ++s) { - if (s->event == event) { - break; - } - } - - // If we don't have a handler, the state machine is borked. - TSReleaseAssert(s != NULL); - TSReleaseAssert(s->handler != NULL); - - // Move to the next state. We have to set this *before* invoking the - // handler because the handler itself can invoke the next handler. - auth->state = s->next; - event = s->handler(auth, edata); - - // If the handler returns TS_EVENT_NONE, it means that a re-entrant event - // was dispatched. In this case, the state machine continues from the - // nested call to dispatch. - if (event == TS_EVENT_NONE) { - return TS_EVENT_NONE; + for (s = auth->state; s && s->event; ++s) { + if (s->event == event) { + break; } + } - // If there are no more states, the state machine has terminated. - if (auth->state == NULL) { - AuthRequestContext::destroy(auth); - return TS_EVENT_NONE; - } + // If we don't have a handler, the state machine is borked. + TSReleaseAssert(s != NULL); + TSReleaseAssert(s->handler != NULL); - // If the handler gave us an event, pump the it back into the current state - // table, otherwise we will return back to the ATS event loop. - if (event != TS_EVENT_CONTINUE) { - goto pump; - } + // Move to the next state. We have to set this *before* invoking the + // handler because the handler itself can invoke the next handler. + auth->state = s->next; + event = s->handler(auth, edata); + // If the handler returns TS_EVENT_NONE, it means that a re-entrant event + // was dispatched. In this case, the state machine continues from the + // nested call to dispatch. + if (event == TS_EVENT_NONE) { return TS_EVENT_NONE; + } + // If there are no more states, the state machine has terminated. + if (auth->state == NULL) { + AuthRequestContext::destroy(auth); + return TS_EVENT_NONE; + } + // If the handler gave us an event, pump the it back into the current state + // table, otherwise we will return back to the ATS event loop. + if (event != TS_EVENT_CONTINUE) { + goto pump; + } + + return TS_EVENT_NONE; } // Return whether the client request was a HEAD request. static bool AuthRequestIsHead(TSHttpTxn txn) { - TSMBuffer mbuf; - TSMLoc mhdr; - int len; - bool is_head; + TSMBuffer mbuf; + TSMLoc mhdr; + int len; + bool is_head; - TSReleaseAssert( - TSHttpTxnClientReqGet(txn, &mbuf, &mhdr) == TS_SUCCESS - ); + TSReleaseAssert(TSHttpTxnClientReqGet(txn, &mbuf, &mhdr) == TS_SUCCESS); - is_head = (TSHttpHdrMethodGet(mbuf, mhdr, &len) == TS_HTTP_METHOD_HEAD); + is_head = (TSHttpHdrMethodGet(mbuf, mhdr, &len) == TS_HTTP_METHOD_HEAD); + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - return is_head; + return is_head; } // Chain the response header hook to send the proxy's authorization response. static void -AuthChainAuthorizationResponse(AuthRequestContext * auth) +AuthChainAuthorizationResponse(AuthRequestContext* auth) { - if (auth->vconn) { - TSVConnClose(auth->vconn); - auth->vconn = NULL; - } + if (auth->vconn) { + TSVConnClose(auth->vconn); + auth->vconn = NULL; + } - TSHttpTxnHookAdd(auth->txn, TS_HTTP_SEND_RESPONSE_HDR_HOOK, auth->cont); - TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_ERROR); + TSHttpTxnHookAdd(auth->txn, TS_HTTP_SEND_RESPONSE_HDR_HOOK, auth->cont); + TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_ERROR); } // Transform the client request into a HEAD request and write it out. static bool -AuthWriteHeadRequest(AuthRequestContext * auth, const sockaddr * /* saddr ATS_UNUSED */) +AuthWriteHeadRequest(AuthRequestContext* auth, const sockaddr* /* saddr ATS_UNUSED */ ) { - HttpHeader rq; - TSMBuffer mbuf; - TSMLoc mhdr; + HttpHeader rq; + TSMBuffer mbuf; + TSMLoc mhdr; - TSReleaseAssert( - TSHttpTxnClientReqGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS - ); + TSReleaseAssert(TSHttpTxnClientReqGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS); - // First, copy the whole client request to our new auth proxy request. - TSReleaseAssert( - TSHttpHdrCopy(rq.buffer, rq.header, mbuf, mhdr) == TS_SUCCESS - ); + // First, copy the whole client request to our new auth proxy request. + TSReleaseAssert(TSHttpHdrCopy(rq.buffer, rq.header, mbuf, mhdr) == TS_SUCCESS); - // Next, we need to rewrite the client request URL to be a HEAD request. - TSReleaseAssert( - TSHttpHdrMethodSet(rq.buffer, rq.header, TS_HTTP_METHOD_HEAD, -1) == TS_SUCCESS - ); + // Next, we need to rewrite the client request URL to be a HEAD request. + TSReleaseAssert(TSHttpHdrMethodSet(rq.buffer, rq.header, TS_HTTP_METHOD_HEAD, -1) == TS_SUCCESS); - HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CONTENT_LENGTH, 0u); - HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CACHE_CONTROL, "no-cache"); + HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CONTENT_LENGTH, 0u); + HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CACHE_CONTROL, "no-cache"); - HttpDebugHeader(rq.buffer, rq.header); + HttpDebugHeader(rq.buffer, rq.header); - // Serialize the HTTP request to the write IO buffer. - TSHttpHdrPrint(rq.buffer, rq.header, auth->iobuf.buffer); + // Serialize the HTTP request to the write IO buffer. + TSHttpHdrPrint(rq.buffer, rq.header, auth->iobuf.buffer); - // We have to tell the auth context not to try to ready the response - // body (since HEAD can have a content-length but must not have any - // content). - auth->read_body = false; + // We have to tell the auth context not to try to ready the response + // body (since HEAD can have a content-length but must not have any + // content). + auth->read_body = false; - TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - return true; + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); + return true; } // Transform the client request into a form that the auth proxy can consume and // write it out. static bool -AuthWriteRedirectedRequest(AuthRequestContext * auth, const sockaddr * saddr) +AuthWriteRedirectedRequest(AuthRequestContext* auth, const sockaddr* saddr) +{ + HttpHeader rq; + TSMBuffer mbuf; + TSMLoc mhdr; + TSMLoc murl; + char addrbuf[INET6_ADDRSTRLEN]; + char hostbuf[INET6_ADDRSTRLEN + sizeof("[]") + sizeof(":65536")]; + uint16_t hostport; + + TSReleaseAssert(TSHttpTxnClientReqGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS); + + // First, copy the whole client request to our new auth proxy request. + TSReleaseAssert(TSHttpHdrCopy(rq.buffer, rq.header, mbuf, mhdr) == TS_SUCCESS); + + hostport = SockaddrGetPort(saddr); + inet_ntop(saddr->sa_family, SockaddrGetAddress(saddr), addrbuf, sizeof(addrbuf)); + if (saddr->sa_family == PF_INET6) { + snprintf(hostbuf, sizeof(hostbuf), "[%s]:%d", addrbuf, hostport); + } else { + snprintf(hostbuf, sizeof(hostbuf), "%s:%d", addrbuf, hostport); + } + + // Next, we need to rewrite the client request URL so that the request goes to + // the auth proxy instead of the original request. + TSReleaseAssert(TSHttpHdrUrlGet(rq.buffer, rq.header, &murl) == TS_SUCCESS); + + // XXX Possibly we should rewrite the URL to remove the host, port and + // scheme, forcing ATS to go to the Host header. I wonder how HTTPS would + // work in that case. At any rate, we should add a new header containing + // the original host so that the auth proxy can examine it. + TSUrlHostSet(rq.buffer, murl, addrbuf, -1); + TSUrlPortSet(rq.buffer, murl, hostport); + TSHandleMLocRelease(rq.buffer, rq.header, murl); + + HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_HOST, hostbuf); + HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CONTENT_LENGTH, 0u); + HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CACHE_CONTROL, "no-cache"); + + HttpDebugHeader(rq.buffer, rq.header); + + // Serialize the HTTP request to the write IO buffer. + TSHttpHdrPrint(rq.buffer, rq.header, auth->iobuf.buffer); + + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); + TSHandleMLocRelease(rq.buffer, rq.header, murl); + return true; +} + +static TSEvent +StateAuthProxyResolve(AuthRequestContext* auth, void*) { - HttpHeader rq; - TSMBuffer mbuf; - TSMLoc mhdr; - TSMLoc murl; - - char addrbuf[INET6_ADDRSTRLEN]; - char hostbuf[INET6_ADDRSTRLEN + sizeof("[]") + sizeof(":65536")]; - uint16_t hostport; - - TSReleaseAssert( - TSHttpTxnClientReqGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS - ); - - // First, copy the whole client request to our new auth proxy request. - TSReleaseAssert( - TSHttpHdrCopy(rq.buffer, rq.header, mbuf, mhdr) == TS_SUCCESS - ); - - hostport = SockaddrGetPort(saddr); - inet_ntop(saddr->sa_family, SockaddrGetAddress(saddr), addrbuf, sizeof(addrbuf)); - if (saddr->sa_family == PF_INET6) { - snprintf(hostbuf, sizeof(hostbuf), "[%s]:%d", addrbuf, hostport); - } else { - snprintf(hostbuf, sizeof(hostbuf), "%s:%d", addrbuf, hostport); - } + TSAction lookup; + const AuthOptions* options = auth->options(); - // Next, we need to rewrite the client request URL so that the request goes to - // the auth proxy instead of the original request. - TSReleaseAssert( - TSHttpHdrUrlGet(rq.buffer, rq.header, &murl) == TS_SUCCESS - ); + // If we are authorizing with a HEAD request we want to send that to the + // origin; other requests we want to send to the authorization proxy. + if (options->transform == AuthWriteHeadRequest) { + char hostname[TS_MAX_HOST_NAME_LEN * 2]; + TSMBuffer mbuf; + TSMLoc mhdr; - // XXX Possibly we should rewrite the URL to remove the host, port and - // scheme, forcing ATS to go to the Host header. I wonder how HTTPS would - // work in that case. At any rate, we should add a new header containing - // the original host so that the auth proxy can examine it. - TSUrlHostSet(rq.buffer, murl, addrbuf, -1); - TSUrlPortSet(rq.buffer, murl, hostport); - TSHandleMLocRelease(rq.buffer,rq.header, murl); + TSReleaseAssert(TSHttpTxnClientReqGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS); - HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_HOST, hostbuf); - HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CONTENT_LENGTH, 0u); - HttpSetMimeHeader(rq.buffer, rq.header, TS_MIME_FIELD_CACHE_CONTROL, "no-cache"); + if (HttpGetOriginHost(mbuf, mhdr, hostname, sizeof(hostname))) { + AuthLogDebug("resolving authorization host %s", hostname); + lookup = TSHostLookup(auth->cont, hostname, strlen(hostname)); + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); + } else { + AuthLogError("failed to extract origin host name from client request"); + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); + return TS_EVENT_ERROR; + } - HttpDebugHeader(rq.buffer, rq.header); + } else { + AuthLogDebug("resolving authorization proxy host %s", options->hostname); + lookup = TSHostLookup(auth->cont, options->hostname, strlen(options->hostname)); + } - // Serialize the HTTP request to the write IO buffer. - TSHttpHdrPrint(rq.buffer, rq.header, auth->iobuf.buffer); + if (TSActionDone(lookup)) { + AuthLogDebug("host lookup was executed in line"); + return TS_EVENT_NONE; + } - TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - TSHandleMLocRelease(rq.buffer, rq.header, murl); - return true; + return TS_EVENT_CONTINUE; } static TSEvent -StateAuthProxyResolve(AuthRequestContext * auth, void *) -{ - TSAction lookup; - const AuthOptions * options = auth->options(); - - // If we are authorizing with a HEAD request we want to send that to the - // origin; other requests we want to send to the authorization proxy. - if (options->transform == AuthWriteHeadRequest) { - char hostname[TS_MAX_HOST_NAME_LEN * 2]; - TSMBuffer mbuf; - TSMLoc mhdr; - - TSReleaseAssert( - TSHttpTxnClientReqGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS - ); - - if (HttpGetOriginHost(mbuf, mhdr, hostname, sizeof(hostname))) { - AuthLogDebug("resolving authorization host %s", hostname); - lookup = TSHostLookup(auth->cont, hostname, strlen(hostname)); - TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - } else { - AuthLogError("failed to extract origin host name from client request"); - TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - return TS_EVENT_ERROR; - } - - } else { - AuthLogDebug("resolving authorization proxy host %s", options->hostname); - lookup = TSHostLookup(auth->cont, options->hostname, strlen(options->hostname)); - } - - if (TSActionDone(lookup)) { - AuthLogDebug("host lookup was executed in line"); - return TS_EVENT_NONE; - } - - return TS_EVENT_CONTINUE; +StateAuthProxyConnect(AuthRequestContext* auth, void* edata) +{ + const AuthOptions* options = auth->options(); + TSHostLookupResult dns; + const sockaddr* saddr; + + union + { + sockaddr sa; + sockaddr_in sin; + sockaddr_in6 sin6; + sockaddr_storage storage; + } addr; + + dns = (TSHostLookupResult) edata; + if (dns == NULL) { + AuthLogError("failed to resolve authorization proxy at %s", options->hostname); + return TS_EVENT_ERROR; + } + // Copy the resolved address and add the port. + saddr = TSHostLookupResultAddrGet(dns); + switch (saddr->sa_family) { + case PF_INET: + memcpy(&addr.sin, saddr, sizeof(sockaddr_in)); + addr.sin.sin_port = options->hostport; + break; + case PF_INET6: + memcpy(&addr.sin6, saddr, sizeof(sockaddr_in6)); + addr.sin6.sin6_port = options->hostport; + break; + } + + auth->is_head = AuthRequestIsHead(auth->txn); + AuthLogDebug("client request %s a HEAD request", auth->is_head ? "is" : "is not"); + + auth->vconn = TSHttpConnect(&addr.sa); + if (auth->vconn == NULL) { + return TS_EVENT_ERROR; + } + // Transform the client request into an auth proxy request and write it + // out to the auth proxy vconn. + if (!options->transform(auth, &addr.sa)) { + return TS_EVENT_ERROR; + } + // Start a write and transition to WriteAuthProxyState. + TSVConnWrite(auth->vconn, auth->cont, auth->iobuf.reader, TSIOBufferReaderAvail(auth->iobuf.reader)); + return TS_EVENT_CONTINUE; } static TSEvent -StateAuthProxyConnect(AuthRequestContext * auth, void * edata) +StateAuthProxyCompleteHeaders(AuthRequestContext* auth, void* /* edata ATS_UNUSED */ ) { - const AuthOptions * options = auth->options(); - TSHostLookupResult dns; - const sockaddr * saddr; - - union { - sockaddr sa; - sockaddr_in sin; - sockaddr_in6 sin6; - sockaddr_storage storage; - } addr; - - dns = (TSHostLookupResult)edata; - if (dns == NULL) { - AuthLogError("failed to resolve authorization proxy at %s", options->hostname); - return TS_EVENT_ERROR; - } + TSHttpStatus status; + unsigned nbytes; - // Copy the resolved address and add the port. - saddr = TSHostLookupResultAddrGet(dns); - switch (saddr->sa_family) { - case PF_INET: - memcpy(&addr.sin, saddr, sizeof(sockaddr_in)); - addr.sin.sin_port = options->hostport; - break; - case PF_INET6: - memcpy(&addr.sin6, saddr, sizeof(sockaddr_in6)); - addr.sin6.sin6_port = options->hostport; - break; - } + HttpDebugHeader(auth->rheader.buffer, auth->rheader.header); - auth->is_head = AuthRequestIsHead(auth->txn); - AuthLogDebug("client request %s a HEAD request", auth->is_head ? "is" : "is not"); + status = TSHttpHdrStatusGet(auth->rheader.buffer, auth->rheader.header); + AuthLogDebug("authorization proxy returned status %d", (int) status); - auth->vconn = TSHttpConnect(&addr.sa); - if (auth->vconn == NULL) { - return TS_EVENT_ERROR; - } + // Authorize the original request on a 2xx response. + if (status >= 200 && status < 300) { + return TS_EVENT_IMMEDIATE; + } - // Transform the client request into an auth proxy request and write it - // out to the auth proxy vconn. - if (!options->transform(auth, &addr.sa)) { - return TS_EVENT_ERROR; + if (auth->read_body) { + // We can't support sending the auth proxy response back to the client + // without writing a transform. Since that's more trouble than I want to + // deal with right now, let's just fail fast ... + if (HttpIsChunkedEncoding(auth->rheader.buffer, auth->rheader.header)) { + AuthLogDebug("ignoring chunked authorization proxy response"); + } else { + // OK, we have a non-chunked response. If there's any content, let's go and + // buffer it so that we can send it on to the client. + nbytes = HttpGetContentLength(auth->rheader.buffer, auth->rheader.header); + if (nbytes > 0) { + AuthLogDebug("content length is %u", nbytes); + return TS_EVENT_HTTP_CONTINUE; + } } - - // Start a write and transition to WriteAuthProxyState. - TSVConnWrite(auth->vconn, auth->cont, auth->iobuf.reader, TSIOBufferReaderAvail(auth->iobuf.reader)); - return TS_EVENT_CONTINUE; + } + // We are going to reply with the auth proxy's response. The response body + // is empty in this case. + AuthChainAuthorizationResponse(auth); + return TS_EVENT_HTTP_SEND_RESPONSE_HDR; } static TSEvent -StateAuthProxyCompleteHeaders(AuthRequestContext * auth, void * /* edata ATS_UNUSED */) +StateAuthProxySendResponse(AuthRequestContext* auth, void* /* edata ATS_UNUSED */ ) { - TSHttpStatus status; - unsigned nbytes; + TSMBuffer mbuf; + TSMLoc mhdr; + TSHttpStatus status; + char msg[128]; - HttpDebugHeader(auth->rheader.buffer, auth->rheader.header); + // The auth proxy denied this request. We need to copy the auth proxy + // response header to the client response header, then read any available + // body data and copy that as well. - status = TSHttpHdrStatusGet(auth->rheader.buffer, auth->rheader.header); - AuthLogDebug("authorization proxy returned status %d", (int)status); + // There's only a client response if the auth proxy sent one. There + TSReleaseAssert(TSHttpTxnClientRespGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS); - // Authorize the original request on a 2xx response. - if (status >= 200 && status < 300) { - return TS_EVENT_IMMEDIATE; - } + TSReleaseAssert(TSHttpHdrCopy(mbuf, mhdr, auth->rheader.buffer, auth->rheader.header) == TS_SUCCESS); - if (auth->read_body) { - // We can't support sending the auth proxy response back to the client - // without writing a transform. Since that's more trouble than I want to - // deal with right now, let's just fail fast ... - if (HttpIsChunkedEncoding(auth->rheader.buffer, auth->rheader.header)) { - AuthLogDebug("ignoring chunked authorization proxy response"); - } else { - // OK, we have a non-chunked response. If there's any content, let's go and - // buffer it so that we can send it on to the client. - nbytes = HttpGetContentLength(auth->rheader.buffer, auth->rheader.header); - if (nbytes > 0) { - AuthLogDebug("content length is %u", nbytes); - return TS_EVENT_HTTP_CONTINUE; - } - } - } + status = TSHttpHdrStatusGet(mbuf, mhdr), snprintf(msg, sizeof(msg), "%d %s\n", status, TSHttpHdrReasonLookup(status)); - // We are going to reply with the auth proxy's response. The response body - // is empty in this case. - AuthChainAuthorizationResponse(auth); - return TS_EVENT_HTTP_SEND_RESPONSE_HDR; -} + TSHttpTxnErrorBodySet(auth->txn, TSstrdup(msg), strlen(msg), TSstrdup("text/plain")); -static TSEvent -StateAuthProxySendResponse(AuthRequestContext * auth, void * /* edata ATS_UNUSED */) -{ - TSMBuffer mbuf; - TSMLoc mhdr; - TSHttpStatus status; - char msg[128]; + // We must not whack the content length for HEAD responses, since the + // client already knows that there is no body. Forcing content length to + // zero breaks hdiutil(1) on Mac OS X. + if (!auth->is_head) { + HttpSetMimeHeader(mbuf, mhdr, TS_MIME_FIELD_CONTENT_LENGTH, 0u); + } - // The auth proxy denied this request. We need to copy the auth proxy - // response header to the client response header, then read any available - // body data and copy that as well. + AuthLogDebug("sending auth proxy response for status %d", status); - // There's only a client response if the auth proxy sent one. There - TSReleaseAssert( - TSHttpTxnClientRespGet(auth->txn, &mbuf, &mhdr) == TS_SUCCESS - ); + TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_CONTINUE); + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); + return TS_EVENT_CONTINUE; +} - TSReleaseAssert( - TSHttpHdrCopy(mbuf, mhdr, auth->rheader.buffer, auth->rheader.header) == TS_SUCCESS - ); +static TSEvent +StateAuthProxyReadHeaders(AuthRequestContext* auth, void* /* edata ATS_UNUSED */ ) +{ + TSIOBufferBlock blk; + ssize_t consumed = 0; + bool complete = false; - status = TSHttpHdrStatusGet(mbuf, mhdr), - snprintf(msg, sizeof(msg), "%d %s\n", status, TSHttpHdrReasonLookup(status)); + AuthLogDebug("reading header data, %u bytes available", (unsigned) TSIOBufferReaderAvail(auth->iobuf.reader)); - TSHttpTxnErrorBodySet(auth->txn, TSstrdup(msg), strlen(msg), TSstrdup("text/plain")); + for (blk = TSIOBufferReaderStart(auth->iobuf.reader); blk; blk = TSIOBufferBlockNext(blk)) { + const char* ptr; + const char* end; + int64_t nbytes; + TSParseResult result; - // We must not whack the content length for HEAD responses, since the - // client already knows that there is no body. Forcing content length to - // zero breaks hdiutil(1) on Mac OS X. - if (!auth->is_head) { - HttpSetMimeHeader(mbuf, mhdr, TS_MIME_FIELD_CONTENT_LENGTH, 0u); + ptr = TSIOBufferBlockReadStart(blk, auth->iobuf.reader, &nbytes); + if (ptr == NULL || nbytes == 0) { + continue; } - AuthLogDebug("sending auth proxy response for status %d", status); - - TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_CONTINUE); - TSHandleMLocRelease(mbuf, TS_NULL_MLOC, mhdr); - return TS_EVENT_CONTINUE; -} + end = ptr + nbytes; + result = TSHttpHdrParseResp(auth->hparser, auth->rheader.buffer, auth->rheader.header, &ptr, end); + switch (result) { + case TS_PARSE_ERROR: + return TS_EVENT_ERROR; + case TS_PARSE_DONE: + case TS_PARSE_OK: + // We consumed the buffer we got minus the remainder. + consumed += (nbytes - std::distance(ptr, end)); + complete = true; + break; + case TS_PARSE_CONT: + consumed += (nbytes - std::distance(ptr, end)); + break; + } -static TSEvent -StateAuthProxyReadHeaders(AuthRequestContext * auth, void * /* edata ATS_UNUSED */) -{ - TSIOBufferBlock blk; - ssize_t consumed = 0; - bool complete = false; - - AuthLogDebug("reading header data, %u bytes available", (unsigned)TSIOBufferReaderAvail(auth->iobuf.reader)); - - for (blk = TSIOBufferReaderStart(auth->iobuf.reader); blk; blk = TSIOBufferBlockNext(blk)) { - const char * ptr; - const char * end; - int64_t nbytes; - TSParseResult result; - - ptr = TSIOBufferBlockReadStart(blk, auth->iobuf.reader, &nbytes); - if (ptr == NULL || nbytes == 0) { - continue; - } - - end = ptr + nbytes; - result = TSHttpHdrParseResp(auth->hparser, auth->rheader.buffer, auth->rheader.header, &ptr, end); - switch (result) { - case TS_PARSE_ERROR: - return TS_EVENT_ERROR; - case TS_PARSE_DONE: - case TS_PARSE_OK: - // We consumed the buffer we got minus the remainder. - consumed += (nbytes - std::distance(ptr, end)); - complete = true; - break; - case TS_PARSE_CONT: - consumed += (nbytes - std::distance(ptr, end)); - break; - } - - if (complete) { - break; - } + if (complete) { + break; } + } - AuthLogDebug("consuming %u bytes, %u remain", - (unsigned)consumed, (unsigned)TSIOBufferReaderAvail(auth->iobuf.reader)); - TSIOBufferReaderConsume(auth->iobuf.reader, consumed); + AuthLogDebug("consuming %u bytes, %u remain", + (unsigned) consumed, (unsigned) TSIOBufferReaderAvail(auth->iobuf.reader)); + TSIOBufferReaderConsume(auth->iobuf.reader, consumed); - // If the headers are complete, send a completion event. - return complete ? TS_EVENT_HTTP_READ_REQUEST_HDR : TS_EVENT_CONTINUE; + // If the headers are complete, send a completion event. + return complete ? TS_EVENT_HTTP_READ_REQUEST_HDR : TS_EVENT_CONTINUE; } static TSEvent -StateAuthProxyWriteComplete(AuthRequestContext * auth, void * /* edata ATS_UNUSED */) +StateAuthProxyWriteComplete(AuthRequestContext* auth, void* /* edata ATS_UNUSED */ ) { - // We finished writing the auth proxy request. Kick off a read to get the response. - auth->iobuf.reset(); + // We finished writing the auth proxy request. Kick off a read to get the response. + auth->iobuf.reset(); - TSVConnRead(auth->vconn, auth->cont, auth->iobuf.buffer, std::numeric_limits<int64_t>::max()); + TSVConnRead(auth->vconn, auth->cont, auth->iobuf.buffer, std::numeric_limits < int64_t >::max()); - // XXX Do we need to keep the read and write VIOs and close them? + // XXX Do we need to keep the read and write VIOs and close them? - return TS_EVENT_CONTINUE; + return TS_EVENT_CONTINUE; } static TSEvent -StateAuthProxyReadContent(AuthRequestContext * auth, void * /* edata ATS_UNUSED */) +StateAuthProxyReadContent(AuthRequestContext* auth, void* /* edata ATS_UNUSED */ ) { - unsigned needed; - int64_t avail = 0; + unsigned needed; + int64_t avail = 0; - avail = TSIOBufferReaderAvail(auth->iobuf.reader); - needed = HttpGetContentLength(auth->rheader.buffer, auth->rheader.header); + avail = TSIOBufferReaderAvail(auth->iobuf.reader); + needed = HttpGetContentLength(auth->rheader.buffer, auth->rheader.header); - AuthLogDebug("we have %u of %u needed bytes", (unsigned)avail, needed); + AuthLogDebug("we have %u of %u needed bytes", (unsigned) avail, needed); - if (avail >= needed) { - // OK, we have what we need. Let's respond to the client request. - AuthChainAuthorizationResponse(auth); - return TS_EVENT_HTTP_SEND_RESPONSE_HDR; - } + if (avail >= needed) { + // OK, we have what we need. Let's respond to the client request. + AuthChainAuthorizationResponse(auth); + return TS_EVENT_HTTP_SEND_RESPONSE_HDR; + } - return TS_EVENT_CONTINUE; + return TS_EVENT_CONTINUE; } static TSEvent -StateAuthProxyCompleteContent(AuthRequestContext * auth, void * /* edata ATS_UNUSED */) +StateAuthProxyCompleteContent(AuthRequestContext* auth, void* /* edata ATS_UNUSED */ ) { - unsigned needed; - int64_t avail; + unsigned needed; + int64_t avail; - avail = TSIOBufferReaderAvail(auth->iobuf.reader); - needed = HttpGetContentLength(auth->rheader.buffer, auth->rheader.header); + avail = TSIOBufferReaderAvail(auth->iobuf.reader); + needed = HttpGetContentLength(auth->rheader.buffer, auth->rheader.header); - AuthLogDebug("we have %u of %u needed bytes", (unsigned)avail, needed); + AuthLogDebug("we have %u of %u needed bytes", (unsigned) avail, needed); - if (avail >= needed) { - // OK, we have what we need. Let's respond to the client request. - AuthChainAuthorizationResponse(auth); - return TS_EVENT_HTTP_SEND_RESPONSE_HDR; - } - - // We got EOS before reading all the content we expected. - return TS_EVENT_ERROR; + if (avail >= needed) { + // OK, we have what we need. Let's respond to the client request. + AuthChainAuthorizationResponse(auth); + return TS_EVENT_HTTP_SEND_RESPONSE_HDR; + } + // We got EOS before reading all the content we expected. + return TS_EVENT_ERROR; } // Terminal state. Force a 403 Forbidden response. static TSEvent -StateUnauthorized(AuthRequestContext * auth, void *) +StateUnauthorized(AuthRequestContext* auth, void*) { - static const char msg[] = "authorization denied\n"; + static const char msg[] = "authorization denied\n"; - TSHttpTxnSetHttpRetStatus(auth->txn, TS_HTTP_STATUS_FORBIDDEN); - TSHttpTxnErrorBodySet(auth->txn, TSstrdup(msg), sizeof(msg) - 1, TSstrdup("text/plain")); + TSHttpTxnSetHttpRetStatus(auth->txn, TS_HTTP_STATUS_FORBIDDEN); + TSHttpTxnErrorBodySet(auth->txn, TSstrdup(msg), sizeof(msg) - 1, TSstrdup("text/plain")); - TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_ERROR); - return TS_EVENT_CONTINUE; + TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_ERROR); + return TS_EVENT_CONTINUE; } // Terminal state. Allow the original request to proceed. static TSEvent -StateAuthorized(AuthRequestContext * auth, void *) +StateAuthorized(AuthRequestContext* auth, void*) { - const AuthOptions * options = auth->options(); + const AuthOptions* options = auth->options(); - AuthLogDebug("request authorized"); + AuthLogDebug("request authorized"); - // Since the original request might have authentication headers, we may - // need to force ATS to ignore those in order to make it cacheable. - if (options->force) { - TSHttpTxnConfigIntSet(auth->txn, TS_CONFIG_HTTP_CACHE_IGNORE_AUTHENTICATION, 1); - } + // Since the original request might have authentication headers, we may + // need to force ATS to ignore those in order to make it cacheable. + if (options->force) { + TSHttpTxnConfigIntSet(auth->txn, TS_CONFIG_HTTP_CACHE_IGNORE_AUTHENTICATION, 1); + } - TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_CONTINUE); - return TS_EVENT_CONTINUE; + TSHttpTxnReenable(auth->txn, TS_EVENT_HTTP_CONTINUE); + return TS_EVENT_CONTINUE; } // Return true if the given request was tagged by a remap rule as needing @@ -695,195 +670,187 @@ StateAuthorized(AuthRequestContext * auth, void *) static bool AuthRequestIsTagged(TSHttpTxn txn) { - return AuthTaggedRequestArg != -1 && - TSHttpTxnArgGet(txn, AuthTaggedRequestArg) != NULL; + return AuthTaggedRequestArg != -1 && TSHttpTxnArgGet(txn, AuthTaggedRequestArg) != NULL; } static int -AuthProxyGlobalHook(TSCont /* cont ATS_UNUSED */, TSEvent event, void * edata) -{ - AuthRequestContext * auth; - union { - TSHostLookupResult dns; - TSHttpTxn txn; - void * edata; - } ptr; - - ptr.edata = edata; - AuthLogDebug("handling event=%d edata=%p", (int)event, edata); - - switch (event) { - case TS_EVENT_HTTP_OS_DNS: - // Ignore internal requests since we generated them. - if (TSHttpIsInternalRequest(ptr.txn) == TS_SUCCESS) { - // All our internal requests *must* hit the origin since it is the - // agent that needs to make the authorization decision. We can't - // allow that to be cached. - TSHttpTxnReqCacheableSet(ptr.txn, 0); - - AuthLogDebug("re-enabling internal transaction"); - TSHttpTxnReenable(ptr.txn, TS_EVENT_HTTP_CONTINUE); - return TS_EVENT_NONE; - } - - // Hook this request if we are in global authorization mode or if a - // remap rule tagged it. - if (AuthGlobalOptions != NULL || AuthRequestIsTagged(ptr.txn)) { - auth = AuthRequestContext::allocate(); - auth->state = StateTableInit; - auth->txn = ptr.txn; - return AuthRequestContext::dispatch(auth->cont, event, edata); - } - - // fallthru - - default: - return TS_EVENT_NONE; +AuthProxyGlobalHook(TSCont /* cont ATS_UNUSED */ , TSEvent event, void* edata) +{ + AuthRequestContext* auth; + union + { + TSHostLookupResult dns; + TSHttpTxn txn; + void* edata; + } ptr; + + ptr.edata = edata; + AuthLogDebug("handling event=%d edata=%p", (int) event, edata); + + switch (event) { + case TS_EVENT_HTTP_OS_DNS: + // Ignore internal requests since we generated them. + if (TSHttpIsInternalRequest(ptr.txn) == TS_SUCCESS) { + // All our internal requests *must* hit the origin since it is the + // agent that needs to make the authorization decision. We can't + // allow that to be cached. + TSHttpTxnReqCacheableSet(ptr.txn, 0); + + AuthLogDebug("re-enabling internal transaction"); + TSHttpTxnReenable(ptr.txn, TS_EVENT_HTTP_CONTINUE); + return TS_EVENT_NONE; + } + // Hook this request if we are in global authorization mode or if a + // remap rule tagged it. + if (AuthGlobalOptions != NULL || AuthRequestIsTagged(ptr.txn)) { + auth = AuthRequestContext::allocate(); + auth->state = StateTableInit; + auth->txn = ptr.txn; + return AuthRequestContext::dispatch(auth->cont, event, edata); } + // fallthru + + default: + return TS_EVENT_NONE; + } } -static AuthOptions * -AuthParseOptions(int argc, const char ** argv) +static AuthOptions* +AuthParseOptions(int argc, const char** argv) { // The const_cast<> here is magic to work around a flaw in the definition of struct option // on some platforms (e.g. Solaris / Illumos). On sane platforms (e.g. linux), it'll get // automatically casted back to the const char*, as the struct is defined in <getopt.h>. - static const struct option longopt[] = - { - { const_cast<char *>("auth-host"), required_argument, 0, 'h' }, - { const_cast<char *>("auth-port"), required_argument, 0, 'p' }, - { const_cast<char *>("auth-transform"), required_argument, 0, 't' }, - { const_cast<char *>("force-cacheability"), no_argument, 0, 'c' }, - {0, 0, 0, 0 } - }; - - AuthOptions * options = AuthNew<AuthOptions>(); - - options->transform = AuthWriteRedirectedRequest; - options->hostname = TSstrdup("127.0.0.1"); - - // We might parse arguments multiple times if we are loaded as a global - // plugin and a remap plugin. Reset optind so that getopt_long() does the - // right thing (ie. work instead of crash). - optind = 0; - - for (;;) { - int opt; - - opt = getopt_long(argc, (char * const *)argv, "", longopt, NULL); - switch (opt) { - case 'h': - TSfree(options->hostname); - options->hostname = TSstrdup(optarg); - break; - case 'p': - options->hostport = std::atoi(optarg); - break; - case 'c': - options->force = true; - break; - case 't': - if (strcasecmp(optarg, "redirect") == 0) { - options->transform = AuthWriteRedirectedRequest; - } else if (strcasecmp(optarg, "head") == 0) { - options->transform = AuthWriteHeadRequest; - } else { - AuthLogError("invalid authorization transform '%s'", optarg); - // XXX make this a fatal error? - } - - break; - } - - if (opt == -1) { - break; - } + static const struct option longopt[] = { + { const_cast<char*>("auth-host"), required_argument, 0, 'h' }, + { const_cast<char*>("auth-port"), required_argument, 0, 'p' }, + { const_cast<char*>("auth-transform"), required_argument, 0, 't' }, + { const_cast<char*>("force-cacheability"), no_argument, 0, 'c' }, + { 0, 0, 0, 0 } + }; + + AuthOptions* options = AuthNew<AuthOptions>(); + + options->transform = AuthWriteRedirectedRequest; + options->hostname = TSstrdup("127.0.0.1"); + + // We might parse arguments multiple times if we are loaded as a global + // plugin and a remap plugin. Reset optind so that getopt_long() does the + // right thing (ie. work instead of crash). + optind = 0; + + for (;;) { + int opt; + + opt = getopt_long(argc, (char* const *) argv, "", longopt, NULL); + switch (opt) { + case 'h': + TSfree(options->hostname); + options->hostname = TSstrdup(optarg); + break; + case 'p': + options->hostport = std::atoi(optarg); + break; + case 'c': + options->force = true; + break; + case 't': + if (strcasecmp(optarg, "redirect") == 0) { + options->transform = AuthWriteRedirectedRequest; + } else if (strcasecmp(optarg, "head") == 0) { + options->transform = AuthWriteHeadRequest; + } else { + AuthLogError("invalid authorization transform '%s'", optarg); + // XXX make this a fatal error? + } + + break; } - return options; + if (opt == -1) { + break; + } + } + + return options; } + #undef LONGOPT_OPTION_CAST void -TSPluginInit(int argc, const char *argv[]) +TSPluginInit(int argc, const char* argv[]) { - TSPluginRegistrationInfo info; + TSPluginRegistrationInfo info; - info.plugin_name = (char *)"authproxy"; - info.vendor_name = (char *)"Apache Software Foundation"; - info.support_email = (char *)"[email protected]"; + info.plugin_name = (char *)"authproxy"; + info.vendor_name = (char *)"Apache Software Foundation"; + info.support_email = (char *)"[email protected]"; - if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { - AuthLogError("plugin registration failed"); - } + if (TSPluginRegister(TS_SDK_VERSION_3_0, &info) != TS_SUCCESS) { + AuthLogError("plugin registration failed"); + } - TSReleaseAssert( - TSHttpArgIndexReserve("AuthProxy", "AuthProxy authorization tag", &AuthTaggedRequestArg) == TS_SUCCESS - ); + TSReleaseAssert(TSHttpArgIndexReserve("AuthProxy", "AuthProxy authorization tag", &AuthTaggedRequestArg) == + TS_SUCCESS); - // We are in global mode. Authorize all requests. - AuthTaggedRequestOnly = false; + // We are in global mode. Authorize all requests. + AuthTaggedRequestOnly = false; - AuthOsDnsContinuation = TSContCreate(AuthProxyGlobalHook, NULL); - AuthGlobalOptions = AuthParseOptions(argc, argv); - AuthLogDebug("using authorization proxy at %s:%d", AuthGlobalOptions->hostname, AuthGlobalOptions->hostport); + AuthOsDnsContinuation = TSContCreate(AuthProxyGlobalHook, NULL); + AuthGlobalOptions = AuthParseOptions(argc, argv); + AuthLogDebug("using authorization proxy at %s:%d", AuthGlobalOptions->hostname, AuthGlobalOptions->hostport); - // Catch the DNS hook. This triggers after reading the headers and - // resolving the requested host, but before performing any cache lookups. - TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, AuthOsDnsContinuation); + // Catch the DNS hook. This triggers after reading the headers and + // resolving the requested host, but before performing any cache lookups. + TSHttpHookAdd(TS_HTTP_OS_DNS_HOOK, AuthOsDnsContinuation); } TSReturnCode -TSRemapInit(TSRemapInterface * api, char * err, int errsz) +TSRemapInit(TSRemapInterface* /* api ATS_UNUSED */, char* /* err ATS_UNUSED */, int /* errsz ATS_UNUSED */) { - (void)api; - (void)err; - (void)errsz; - - TSReleaseAssert( - TSHttpArgIndexReserve("AuthProxy", "AuthProxy authorization tag", &AuthTaggedRequestArg) == TS_SUCCESS - ); - - // We are in remap mode. Only authorize tagged requests. - AuthTaggedRequestOnly = true; - AuthOsDnsContinuation = TSContCreate(AuthProxyGlobalHook, NULL); - return TS_SUCCESS; + TSReleaseAssert(TSHttpArgIndexReserve("AuthProxy", "AuthProxy authorization tag", &AuthTaggedRequestArg) == + TS_SUCCESS); + + // We are in remap mode. Only authorize tagged requests. + AuthTaggedRequestOnly = true; + AuthOsDnsContinuation = TSContCreate(AuthProxyGlobalHook, NULL); + return TS_SUCCESS; } TSReturnCode -TSRemapNewInstance(int argc, char * argv[], void ** instance, char * /* err ATS_UNUSED */, int /* errsz ATS_UNUSED */) +TSRemapNewInstance(int argc, char* argv[], void** instance, char* /* err ATS_UNUSED */ , int /* errsz ATS_UNUSED */ ) { - AuthOptions * options; + AuthOptions* options; - AuthLogDebug("using authorization proxy for remapping %s -> %s", argv[0], argv[1]); + AuthLogDebug("using authorization proxy for remapping %s -> %s", argv[0], argv[1]); - // The first two arguments are the "from" and "to" URL string. We need to - // skip them, but we also require that there be an option to masquerade as - // argv[0], so we increment the argument indexes by 1 rather than by 2. - argc--; - argv++; - options = AuthParseOptions(argc, (const char **)argv); + // The first two arguments are the "from" and "to" URL string. We need to + // skip them, but we also require that there be an option to masquerade as + // argv[0], so we increment the argument indexes by 1 rather than by 2. + argc--; + argv++; + options = AuthParseOptions(argc, (const char**) argv); - *instance = options; - return TS_SUCCESS; + *instance = options; + return TS_SUCCESS; } void -TSRemapDeleteInstance(void * instance) +TSRemapDeleteInstance(void* instance) { - AuthOptions * options = (AuthOptions *)instance; - AuthDelete(options); + AuthOptions* options = (AuthOptions* ) instance; + AuthDelete(options); } TSRemapStatus -TSRemapDoRemap(void * instance, TSHttpTxn txn, TSRemapRequestInfo * /* rri ATS_UNUSED */) +TSRemapDoRemap(void* instance, TSHttpTxn txn, TSRemapRequestInfo* /* rri ATS_UNUSED */ ) { - AuthOptions * options = (AuthOptions *)instance; + AuthOptions* options = (AuthOptions*) instance; - TSHttpTxnArgSet(txn, AuthTaggedRequestArg, options); - TSHttpTxnHookAdd(txn, TS_HTTP_OS_DNS_HOOK, AuthOsDnsContinuation); - return TSREMAP_NO_REMAP; + TSHttpTxnArgSet(txn, AuthTaggedRequestArg, options); + TSHttpTxnHookAdd(txn, TS_HTTP_OS_DNS_HOOK, AuthOsDnsContinuation); + return TSREMAP_NO_REMAP; } // vim: set ts=4 sw=4 et : http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4b2429b6/plugins/experimental/authproxy/utils.cc ---------------------------------------------------------------------- diff --git a/plugins/experimental/authproxy/utils.cc b/plugins/experimental/authproxy/utils.cc index d55e1af..8211b8f 100644 --- a/plugins/experimental/authproxy/utils.cc +++ b/plugins/experimental/authproxy/utils.cc @@ -27,190 +27,173 @@ #include <netinet/in.h> #include <arpa/inet.h> -const void * -SockaddrGetAddress(const sockaddr * saddr) +const void* +SockaddrGetAddress(const sockaddr* saddr) { - union { - const sockaddr * sa; - const sockaddr_in * sin; - const sockaddr_in6 * sin6; - } addr; - - addr.sa = saddr; - if (addr.sa->sa_family == PF_INET6) { - return &addr.sin6->sin6_addr; - } else { - TSReleaseAssert(addr.sin->sin_family == PF_INET); - return &addr.sin->sin_addr; - } + union + { + const sockaddr* sa; + const sockaddr_in* sin; + const sockaddr_in6* sin6; + } addr; + + addr.sa = saddr; + if (addr.sa->sa_family == PF_INET6) { + return &addr.sin6->sin6_addr; + } else { + TSReleaseAssert(addr.sin->sin_family == PF_INET); + return &addr.sin->sin_addr; + } } uint16_t -SockaddrGetPort(const sockaddr * saddr) +SockaddrGetPort(const sockaddr* saddr) { - union { - const sockaddr * sa; - const sockaddr_in * sin; - const sockaddr_in6 * sin6; - } addr; - - addr.sa = saddr; - if (addr.sa->sa_family == PF_INET6) { - return addr.sin6->sin6_port; - } else { - TSReleaseAssert(addr.sin->sin_family == PF_INET); - return addr.sin->sin_port; - } + union + { + const sockaddr* sa; + const sockaddr_in* sin; + const sockaddr_in6* sin6; + } addr; + + addr.sa = saddr; + if (addr.sa->sa_family == PF_INET6) { + return addr.sin6->sin6_port; + } else { + TSReleaseAssert(addr.sin->sin_family == PF_INET); + return addr.sin->sin_port; + } } void HttpDebugHeader(TSMBuffer mbuf, TSMLoc mhdr) { - HttpIoBuffer iobuf; - int64_t nbytes; - int64_t avail; - const char * ptr; - TSIOBufferBlock blk; + HttpIoBuffer iobuf; + int64_t nbytes; + int64_t avail; + const char* ptr; + TSIOBufferBlock blk; - TSHttpHdrPrint(mbuf, mhdr, iobuf.buffer); + TSHttpHdrPrint(mbuf, mhdr, iobuf.buffer); - blk = TSIOBufferReaderStart(iobuf.reader); - avail = TSIOBufferBlockReadAvail(blk, iobuf.reader); - ptr = (const char *)TSIOBufferBlockReadStart(blk, iobuf.reader, &nbytes); + blk = TSIOBufferReaderStart(iobuf.reader); + avail = TSIOBufferBlockReadAvail(blk, iobuf.reader); + ptr = (const char*) TSIOBufferBlockReadStart(blk, iobuf.reader, &nbytes); - AuthLogDebug( - "http request (%u of %u bytes):\n%*.*s", - (unsigned)nbytes, (unsigned)avail, (int)nbytes, (int)nbytes, ptr); + AuthLogDebug("http request (%u of %u bytes):\n%*.*s", + (unsigned) nbytes, (unsigned) avail, (int) nbytes, (int) nbytes, ptr); } void -HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char * name, unsigned value) +HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char* name, unsigned value) { - TSMLoc mloc; - - mloc = TSMimeHdrFieldFind(mbuf, mhdr, name, -1); - if (mloc == TS_NULL_MLOC) { - TSReleaseAssert( - TSMimeHdrFieldCreateNamed(mbuf, mhdr, name, -1, &mloc) == TS_SUCCESS - ); - } else { - TSReleaseAssert( - TSMimeHdrFieldValuesClear(mbuf, mhdr, mloc) == TS_SUCCESS - ); - } + TSMLoc mloc; - TSReleaseAssert( - TSMimeHdrFieldValueUintInsert(mbuf, mhdr, mloc, 0 /* index */, value) == TS_SUCCESS - ); + mloc = TSMimeHdrFieldFind(mbuf, mhdr, name, -1); + if (mloc == TS_NULL_MLOC) { + TSReleaseAssert(TSMimeHdrFieldCreateNamed(mbuf, mhdr, name, -1, &mloc) == TS_SUCCESS); + } else { + TSReleaseAssert(TSMimeHdrFieldValuesClear(mbuf, mhdr, mloc) == TS_SUCCESS); + } - TSReleaseAssert( - TSMimeHdrFieldAppend(mbuf, mhdr, mloc) == TS_SUCCESS - ); + TSReleaseAssert(TSMimeHdrFieldValueUintInsert(mbuf, mhdr, mloc, 0 /* index */ , value) == TS_SUCCESS); + TSReleaseAssert(TSMimeHdrFieldAppend(mbuf, mhdr, mloc) == TS_SUCCESS); - TSHandleMLocRelease(mbuf, mhdr, mloc); + TSHandleMLocRelease(mbuf, mhdr, mloc); } void -HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char * name, const char * value) +HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char* name, const char* value) { - TSMLoc mloc; - - mloc = TSMimeHdrFieldFind(mbuf, mhdr, name, -1); - if (mloc == TS_NULL_MLOC) { - TSReleaseAssert( - TSMimeHdrFieldCreateNamed(mbuf, mhdr, name, -1, &mloc) == TS_SUCCESS - ); - } else { - TSReleaseAssert( - TSMimeHdrFieldValuesClear(mbuf, mhdr, mloc) == TS_SUCCESS - ); - } + TSMLoc mloc; - TSReleaseAssert( - TSMimeHdrFieldValueStringInsert(mbuf, mhdr, mloc, 0 /* index */, value, -1) == TS_SUCCESS - ); + mloc = TSMimeHdrFieldFind(mbuf, mhdr, name, -1); + if (mloc == TS_NULL_MLOC) { + TSReleaseAssert(TSMimeHdrFieldCreateNamed(mbuf, mhdr, name, -1, &mloc) == TS_SUCCESS); + } else { + TSReleaseAssert(TSMimeHdrFieldValuesClear(mbuf, mhdr, mloc) == TS_SUCCESS); + } - TSReleaseAssert( - TSMimeHdrFieldAppend(mbuf, mhdr, mloc) == TS_SUCCESS - ); + TSReleaseAssert(TSMimeHdrFieldValueStringInsert(mbuf, mhdr, mloc, 0 /* index */ , value, -1) == TS_SUCCESS); + TSReleaseAssert(TSMimeHdrFieldAppend(mbuf, mhdr, mloc) == TS_SUCCESS); - TSHandleMLocRelease(mbuf, mhdr, mloc); + TSHandleMLocRelease(mbuf, mhdr, mloc); } unsigned HttpGetContentLength(TSMBuffer mbuf, TSMLoc mhdr) { - TSMLoc mloc; - unsigned value = 0; + TSMLoc mloc; + unsigned value = 0; - mloc = TSMimeHdrFieldFind(mbuf, mhdr, TS_MIME_FIELD_CONTENT_LENGTH, -1); - if (mloc != TS_NULL_MLOC) { - value = TSMimeHdrFieldValueUintGet(mbuf, mhdr, mloc, 0 /* index */); - } + mloc = TSMimeHdrFieldFind(mbuf, mhdr, TS_MIME_FIELD_CONTENT_LENGTH, -1); + if (mloc != TS_NULL_MLOC) { + value = TSMimeHdrFieldValueUintGet(mbuf, mhdr, mloc, 0 /* index */ ); + } - TSHandleMLocRelease(mbuf, mhdr, mloc); - return value; + TSHandleMLocRelease(mbuf, mhdr, mloc); + return value; } bool HttpIsChunkedEncoding(TSMBuffer mbuf, TSMLoc mhdr) { - TSMLoc mloc; - bool ischunked = false; - - mloc = TSMimeHdrFieldFind(mbuf, mhdr, TS_MIME_FIELD_TRANSFER_ENCODING, -1); - if (mloc != TS_NULL_MLOC) { - const char * str; - int len; - - str = TSMimeHdrFieldValueStringGet(mbuf, mhdr, mloc, -1 /* index */, &len); - if (str && len) { - ischunked = (strncmp("chunked", str, len) == 0); - } + TSMLoc mloc; + bool ischunked = false; + + mloc = TSMimeHdrFieldFind(mbuf, mhdr, TS_MIME_FIELD_TRANSFER_ENCODING, -1); + if (mloc != TS_NULL_MLOC) { + const char* str; + int len; + + str = TSMimeHdrFieldValueStringGet(mbuf, mhdr, mloc, -1 /* index */ , &len); + if (str && len) { + ischunked = (strncmp("chunked", str, len) == 0); } + } - TSHandleMLocRelease(mbuf, mhdr, mloc); - return ischunked; + TSHandleMLocRelease(mbuf, mhdr, mloc); + return ischunked; } bool -HttpGetOriginHost(TSMBuffer mbuf, TSMLoc mhdr, char * name, size_t namelen) +HttpGetOriginHost(TSMBuffer mbuf, TSMLoc mhdr, char* name, size_t namelen) { - const char * host; - int len; - TSMLoc mloc; - - // First, try to get it from the Host header. The Host header this returns - // depends on whether pristine_host_hdr is set. - mloc = TSMimeHdrFieldFind(mbuf, mhdr, TS_MIME_FIELD_HOST, -1); - if (mloc != TS_NULL_MLOC) { - host = TSMimeHdrFieldValueStringGet(mbuf, mhdr, mloc, -1 /* index */, &len); - TSHandleMLocRelease(mbuf, mhdr, mloc); - - if (host) { - AuthLogDebug("using origin %.*s from host header", len, host); - len = std::min(len, (int)namelen - 1); - memcpy(name, host, len); - name[len] = '\0'; - return true; - } + const char* host; + int len; + TSMLoc mloc; + + // First, try to get it from the Host header. The Host header this returns + // depends on whether pristine_host_hdr is set. + mloc = TSMimeHdrFieldFind(mbuf, mhdr, TS_MIME_FIELD_HOST, -1); + if (mloc != TS_NULL_MLOC) { + host = TSMimeHdrFieldValueStringGet(mbuf, mhdr, mloc, -1 /* index */ , &len); + TSHandleMLocRelease(mbuf, mhdr, mloc); + + if (host) { + AuthLogDebug("using origin %.*s from host header", len, host); + len = std::min(len, (int) namelen - 1); + memcpy(name, host, len); + name[len] = '\0'; + return true; } + } + + // If that didn't work, try to get the origin host from the request URL. + if (TSHttpHdrUrlGet(mbuf, mhdr, &mloc) == TS_SUCCESS) { + host = TSUrlHostGet(mbuf, mloc, &len); + TSHandleMLocRelease(mbuf, mhdr, mloc); - // If that didn't work, try to get the origin host from the request URL. - if (TSHttpHdrUrlGet(mbuf, mhdr, &mloc) == TS_SUCCESS) { - host = TSUrlHostGet(mbuf, mloc, &len); - TSHandleMLocRelease(mbuf, mhdr, mloc); - - if (host) { - AuthLogDebug("using origin %.*s from request URL", len, host); - len = std::min(len, (int)namelen - 1); - memcpy(name, host, len); - name[len] = '\0'; - return true; - } + if (host) { + AuthLogDebug("using origin %.*s from request URL", len, host); + len = std::min(len, (int) namelen - 1); + memcpy(name, host, len); + name[len] = '\0'; + return true; } + } - return false; + return false; } // vim: set ts=4 sw=4 et : http://git-wip-us.apache.org/repos/asf/trafficserver/blob/4b2429b6/plugins/experimental/authproxy/utils.h ---------------------------------------------------------------------- diff --git a/plugins/experimental/authproxy/utils.h b/plugins/experimental/authproxy/utils.h index 58880dc..3339975 100644 --- a/plugins/experimental/authproxy/utils.h +++ b/plugins/experimental/authproxy/utils.h @@ -24,66 +24,72 @@ #define AuthLogError(fmt, ...) TSError(fmt, ##__VA_ARGS__) template <typename T> -T * AuthNew() { - return new(TSmalloc(sizeof(T))) T(); +T* AuthNew() +{ + return new(TSmalloc(sizeof(T))) T(); } template <typename T> -void AuthDelete(T * ptr) { - ptr->~T(); - TSfree(ptr); +void +AuthDelete(T* ptr) +{ + ptr->~T(); + TSfree(ptr); } struct HttpIoBuffer { - TSIOBuffer buffer; - TSIOBufferReader reader; - - explicit HttpIoBuffer(TSIOBufferSizeIndex size = TS_IOBUFFER_SIZE_INDEX_32K) { - this->buffer = TSIOBufferSizedCreate(size); - this->reader = TSIOBufferReaderAlloc(this->buffer); - } - - ~HttpIoBuffer() { - TSIOBufferReaderFree(this->reader); - TSIOBufferDestroy(this->buffer); - } - - void reset(TSIOBufferSizeIndex size = TS_IOBUFFER_SIZE_INDEX_32K) { - TSIOBufferReaderFree(this->reader); - TSIOBufferDestroy(this->buffer); - this->buffer = TSIOBufferSizedCreate(size); - this->reader = TSIOBufferReaderAlloc(this->buffer); - } - - void consume(size_t nbytes) { - TSIOBufferReaderConsume(this->reader, nbytes); - } + TSIOBuffer buffer; + TSIOBufferReader reader; + + explicit HttpIoBuffer(TSIOBufferSizeIndex size = TS_IOBUFFER_SIZE_INDEX_32K) { + this->buffer = TSIOBufferSizedCreate(size); + this->reader = TSIOBufferReaderAlloc(this->buffer); + } + + ~HttpIoBuffer() + { + TSIOBufferReaderFree(this->reader); + TSIOBufferDestroy(this->buffer); + } + + void reset(TSIOBufferSizeIndex size = TS_IOBUFFER_SIZE_INDEX_32K) { + TSIOBufferReaderFree(this->reader); + TSIOBufferDestroy(this->buffer); + this->buffer = TSIOBufferSizedCreate(size); + this->reader = TSIOBufferReaderAlloc(this->buffer); + } + + void consume(size_t nbytes) + { + TSIOBufferReaderConsume(this->reader, nbytes); + } private: - HttpIoBuffer(const HttpIoBuffer&); //delete - HttpIoBuffer& operator=(const HttpIoBuffer&); //delete + HttpIoBuffer(const HttpIoBuffer &); //delete + HttpIoBuffer & operator=(const HttpIoBuffer &); //delete }; struct HttpHeader { - HttpHeader() - : buffer(TSMBufferCreate()), header(TSHttpHdrCreate(buffer)) { - } + HttpHeader() + : buffer(TSMBufferCreate()), header(TSHttpHdrCreate(buffer)) + { } - ~HttpHeader() { - TSHttpHdrDestroy(this->buffer, this->header); + ~HttpHeader() + { + TSHttpHdrDestroy(this->buffer, this->header); - TSHandleMLocRelease(this->buffer, TS_NULL_MLOC, this->header); - TSMBufferDestroy(this->buffer); - } + TSHandleMLocRelease(this->buffer, TS_NULL_MLOC, this->header); + TSMBufferDestroy(this->buffer); + } - TSMBuffer buffer; - TSMLoc header; + TSMBuffer buffer; + TSMLoc header; private: - HttpHeader(const HttpHeader&); // delete - HttpHeader& operator=(const HttpHeader&); // delete + HttpHeader(const HttpHeader &); // delete + HttpHeader & operator=(const HttpHeader &); // delete }; // Return true if the given HTTP header specified chunked transfer encoding. @@ -93,12 +99,12 @@ bool HttpIsChunkedEncoding(TSMBuffer mbuf, TSMLoc mhdr); unsigned HttpGetContentLength(TSMBuffer mbuf, TSMLoc mhdr); // Set the value of an arbitrary HTTP header. -void HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char * name, const char * value); -void HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char * name, unsigned value); +void HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char *name, const char *value); +void HttpSetMimeHeader(TSMBuffer mbuf, TSMLoc mhdr, const char *name, unsigned value); // Get the origin server name for the given request. Takes the URL and the Host // header into account (preferring the former). -bool HttpGetOriginHost(TSMBuffer mbuf, TSMLoc mhdr, char * name, size_t namelen); +bool HttpGetOriginHost(TSMBuffer mbuf, TSMLoc mhdr, char *name, size_t namelen); // Dump the given HTTP header to the debug log. void HttpDebugHeader(TSMBuffer mbuf, TSMLoc mhdr); @@ -106,6 +112,6 @@ void HttpDebugHeader(TSMBuffer mbuf, TSMLoc mhdr); // Return the sockaddr port (if any); uint16_t SockaddrGetPort(const sockaddr * saddr); // Return a pointer to the sockaddr address. -const void * SockaddrGetAddress(const sockaddr * saddr); +const void *SockaddrGetAddress(const sockaddr * saddr); // vim: set ts=4 sw=4 et :
