From: Dave Pacheco Date: Sat, 4 Jun 2011 14:04:38 +0000 (+0200) Subject: DTrace probes: support X-Forwarded-For X-Git-Tag: v0.5.0~111 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e142fe2be6ef3e5cd27b89d59175a3937b9fdb31;p=platform%2Fupstream%2Fnodejs.git DTrace probes: support X-Forwarded-For INTRO-385 --- diff --git a/src/node.d b/src/node.d index b81930c..c666127 100644 --- a/src/node.d +++ b/src/node.d @@ -65,29 +65,95 @@ translator node_connection_t { }; typedef struct { + uint32_t version; +} node_dtrace_http_request_t; + +typedef struct { uint32_t url; uint32_t method; -} node_dtrace_http_request_t; +} node_dtrace_http_request_v0_t; + +typedef struct { + uint32_t version; + uint32_t url; + uint32_t method; + uint32_t forwardedFor; +} node_dtrace_http_request_v1_t; typedef struct { uint64_t url; uint64_t method; -} node_dtrace_http_request64_t; +} node_dtrace_http_request64_v0_t; + +typedef struct { + uint32_t version; + uint32_t pad; + uint64_t url; + uint64_t method; + uint64_t forwardedFor; +} node_dtrace_http_request64_v1_t; typedef struct { string url; string method; + string forwardedFor; } node_http_request_t; +/* + * This translator is even filthier than usual owing to our attempts to + * maintain backwards compatibility. Previous versions of node used an + * http_request struct that had fields for "url" and "method". The current + * version also provides a "forwardedFor" field. To distinguish the binary + * representations of these structs, the new version also prepends a "version" + * member (where the old one has a "url" pointer). So each field that we're + * translating below first switches on the value of this "version" field: if + * it's larger than 4096, we know we must be looking at the "url" pointer of + * the older structure version. Otherwise, we must be looking at the new + * version. Besides this, we have the usual switch based on the userland + * process data model. This would all be simpler with macros, but those aren't + * available in delivered D library files since that would make DTrace + * dependent on cpp, which isn't always available. + */ translator node_http_request_t { - url = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? - copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t)&nd->url, - sizeof (int32_t))) : - copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_t *)nd)->url, sizeof (int64_t))); - method = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? - copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t)&nd->method, - sizeof (int32_t))) : - copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t) - &((node_dtrace_http_request64_t *)nd)->method, sizeof (int64_t))); + url = (*(uint32_t *)copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_request_v0_t *)nd)->url, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_request64_v0_t *)nd)->url, + sizeof (uint64_t)))) : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_request_v1_t *)nd)->url, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_request64_v1_t *)nd)->url, + sizeof (uint64_t)))); + + method = (*(uint32_t *)copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_request_v0_t *)nd)->method, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_request64_v0_t *)nd)->method, + sizeof (uint64_t)))) : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_request_v1_t *)nd)->method, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_request64_v1_t *)nd)->method, + sizeof (uint64_t)))); + + forwardedFor = (*(uint32_t *) + copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? "" : + (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ? + copyinstr(*(uint32_t *)copyin((uintptr_t) + &((node_dtrace_http_request_v1_t *)nd)->forwardedFor, + sizeof (uint32_t))) : + copyinstr(*(uint64_t *)copyin((uintptr_t) + &((node_dtrace_http_request64_v1_t *)nd)->forwardedFor, + sizeof (uint64_t)))); }; diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index 6481267..ac14bda 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -20,6 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. #include +#include #ifdef HAVE_DTRACE #include "node_provider.h" @@ -180,7 +181,7 @@ Handle DTRACE_NET_SOCKET_WRITE(const Arguments& args) { } Handle DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) { - node_dtrace_http_request_t req; + node_dtrace_http_server_request_t req; if (!NODE_HTTP_SERVER_REQUEST_ENABLED()) return Undefined(); @@ -188,10 +189,25 @@ Handle DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) { HandleScope scope; Local arg0 = Local::Cast(args[0]); + Local headers; + bzero(&req, sizeof(req)); + req._un.version = 1; SLURP_STRING(arg0, url, &req.url); SLURP_STRING(arg0, method, &req.method); + SLURP_OBJECT(arg0, headers, &headers); + + if (!(headers)->IsObject()) + return (ThrowException(Exception::Error(String::New("expected " + "object for request to contain string member headers")))); + + Local strfwdfor = headers->Get(String::New("x-forwarded-for")); + String::Utf8Value fwdfor(strfwdfor->ToString()); + + if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == NULL) + req.forwardedFor = ""; + SLURP_CONNECTION(args[1], conn); NODE_HTTP_SERVER_REQUEST(&req, &conn); @@ -211,7 +227,7 @@ Handle DTRACE_HTTP_SERVER_RESPONSE(const Arguments& args) { } Handle DTRACE_HTTP_CLIENT_REQUEST(const Arguments& args) { - node_dtrace_http_request_t req; + node_dtrace_http_client_request_t req; char *header; if (!NODE_HTTP_CLIENT_REQUEST_ENABLED()) diff --git a/src/node_dtrace.h b/src/node_dtrace.h index 3a916be..f10b267 100644 --- a/src/node_dtrace.h +++ b/src/node_dtrace.h @@ -27,6 +27,14 @@ extern "C" { +/* + * The following structures are passed directly to DTrace when probes are fired. + * Translators in node.d translate these structures into the corresponding D + * structures, taking care of dealing with the user process data model (32-bit + * or 64-bit) and structure versions (see node_dtrace_http_server_request_t + * below). + */ + typedef struct { int32_t fd; int32_t port; @@ -37,7 +45,31 @@ typedef struct { typedef struct { char *url; char *method; -} node_dtrace_http_request_t; +} node_dtrace_http_client_request_t; + +/* + * The original version of this structure contained only a url and method, just + * like the client request above. To add the new forwardedFor field, the + * structure layout was changed to begin with an integer version. The + * translator knows whether it's looking at an old- or new-version structure + * based on whether the version field's value is a reasonable pointer (i.e. + * address greater than 4K). No doubt this is filthy, but there's not much else + * we can do, and it works reliably. + * + * This version of the structure also contains padding that should be zeroed out + * by the consumer so that future versions of the translator can simply check if + * a field is present by checking it against NULL. + */ +typedef struct { + union { + uint32_t version; + uintptr_t unused; /* for compat. with old 64-bit struct */ + } _un; + char *url; + char *method; + char *forwardedFor; + char *_pad[8]; +} node_dtrace_http_server_request_t; } diff --git a/src/node_provider.d b/src/node_provider.d index bea4e5f..646e21a 100644 --- a/src/node_provider.d +++ b/src/node_provider.d @@ -41,7 +41,11 @@ typedef struct { typedef struct { int dummy; -} node_dtrace_http_request_t; +} node_dtrace_http_server_request_t; + +typedef struct { + int dummy; +} node_dtrace_http_client_request_t; typedef struct { int dummy; @@ -56,12 +60,12 @@ provider node { (node_connection_t *c, int b); probe net__socket__write(node_dtrace_connection_t *c, int b) : (node_connection_t *c, int b); - probe http__server__request(node_dtrace_http_request_t *h, + probe http__server__request(node_dtrace_http_server_request_t *h, node_dtrace_connection_t *c) : (node_http_request_t *h, node_connection_t *c); probe http__server__response(node_dtrace_connection_t *c) : (node_connection_t *c); - probe http__client__request(node_dtrace_http_request_t *h, + probe http__client__request(node_dtrace_http_client_request_t *h, node_dtrace_connection_t *c) : (node_http_request_t *h, node_connection_t *c); probe http__client__response(node_dtrace_connection_t *c) :