HTTPS Proxy Configuration (with HTTP Header Modification and URL shortening)
From ContikiWiki
[edit] A simple HTTP proxy for connecting to a remote API server using Nginx
Let's consider the following real-world scenario:
- your ISP doesn't provide IPv6 connectivity
- you don't have a VPS that could be used for tunnelling
- you only want to bind a single remote IPv4 address and local IPv6 address
- what if the API host only accepts HTTPS connections ...
- what if you can use plain HTTP, though you rather not use it ...
Additionally you may wish to:
- avoid the entire chunk of HTTP headers going through to 6loWPAN node
- avoid having to store the API key in the program memory of the node
- shorten the URL suffix or rewrite it for your needs
[edit] Header optimisation
The idea is to avoid transfer of unnecessary information via the 6loWPAN segment.
It appears that Pachube server sends the following reply headers:
% curl -6 http://localhost:82/feeds/504.csv -v * About to connect() to localhost port 82 (#0) * Trying ::1... connected * Connected to localhost (::1) port 82 (#0) > GET /feeds/504.csv HTTP/1.1 > User-Agent: curl/7.21.4 (x86_64-pc-linux-gnu) libcurl/7.21.4 GnuTLS/2.10.5 zlib/1.2.5 libidn/1.22 > Host: localhost:82 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.0.6 < Date: Wed, 02 Nov 2011 18:07:11 GMT < Content-Type: text/plain; charset=utf-8 < Connection: keep-alive < Last-Modified: Wed, 02 Nov 2011 18:07:09 GMT < X-Pachube-Logging-Key: logging.6hLvdI8DjdJP1gRr2X30 < X-PachubeRequestId: 903ed3dea9830689cac1544ac299f08cc9c36df6 < Cache-Control: max-age=5 < Content-Length: 232 < Age: 0 < Vary: Accept-Encoding < 0,2011-11-02T18:07:09.396577Z,18 1,2011-11-02T18:07:09.396577Z,93 2,2011-11-02T18:07:09.396577Z,292 3,2011-11-02T18:07:09.396577Z,0 4,2011-11-02T18:07:09.396577Z,0 5,2011-11-02T18:07:09.396577Z,0 * Connection #0 to host localhost left intact * Closing connection #0 6,2011-11-02T18:07:09.396577Z,-28307
The minimum header that it could be compressed to is:
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Connection: keep-alive
< Content-Length: 232
<
However for HTTP/1.1 compliance this is what has to be there:
< HTTP/1.1 200 OK
< Server: nginx/1.0.6
< Date: Wed, 02 Nov 2011 21:47:05 GMT
< Content-Type: text/plain; charset=utf-8
< Connection: keep-alive
< Content-Length: 22
<
Let's presume that these details will never be of any use:
< Age: 0
< Vary: Accept-Encoding
There is hardly any use for this either:
< Cache-Control: max-age=5
As well as 'Last-Modified', because it is as you notice the same as the second column on the firs line of CSV:
< Last-Modified: Wed, 02 Nov 2011 18:07:09 GMT
I really don't think that this could be used by a node:
< X-Pachube-Logging-Key: logging.6hLvdI8DjdJP1gRr2X30
< X-PachubeRequestId: 903ed3dea9830689cac1544ac299f08cc9c36df6
[edit] Pachube example
This is multi-port configuration, hopefully it is quite self-explanatory. For up-to-date version please see pachube_proxy.conf
user nginx nginx; worker_processes 3;
error_log log/nginx/pachube-api.error_log debug;
events {
worker_connections 1024;
use epoll;
}
http {
upstream pachube-ssl-proxy {
server 173.203.98.29:443;
}
server {
# curl https://api.pachube.com/v1/feeds/504.csv
# curl -6 http://localhost:81/feeds/504.csv
listen [::0]:81;
location / {
proxy_set_header host api.pachube.com;
proxy_set_header X-PachubeApiKey COPY_YOUR_TOP_SECRET_STRING_OF_43_CHARCTERS;
proxy_hide_header Age;
proxy_hide_header Vary;
proxy_hide_header Last-Modified;
proxy_hide_header X-Pachube-Logging-Key;
proxy_hide_header X-PachubeRequestId;
proxy_hide_header Cache-Control;
proxy_pass https://pachube-ssl-proxy/v1/;
}
}
server {
# curl https://api.pachube.com/v2/feeds/504.csv
# curl -6 http://localhost:82/feeds/504.csv
listen [::0]:82;
location / {
proxy_set_header host api.pachube.com;
proxy_set_header X-PachubeApiKey COPY_YOUR_TOP_SECRET_STRING_OF_43_CHARCTERS;
proxy_hide_header Age;
proxy_hide_header Vary;
proxy_hide_header Last-Modified;
proxy_hide_header X-Pachube-Logging-Key;
proxy_hide_header X-PachubeRequestId;
proxy_hide_header Cache-Control;
proxy_pass https://pachube-ssl-proxy/v2/;
}
}
server {
listen [::0]:80;
location / {
proxy_set_header host pachube.com;
proxy_pass https://pachube-ssl-proxy;
}
}
server {
# curl -6 http://localhost:83/504/datastreams/0/history.csv
listen [::0]:83;
location / {
proxy_set_header host pachube.com;
proxy_pass https://pachube-ssl-proxy/feeds/;
}
}
}
It works well with this example (provided you have supplied the API key in the Nginx config).
#include "contiki-net.h"
#include <string.h>
static struct etimer timer;
static struct psock ps;
static char buffer[100];
PROCESS(example_psock_client_process, "Pachube test client");
AUTOSTART_PROCESSES(&example_psock_client_process);
/*---------------------------------------------------------------------------*/
static int
handle_connection(struct psock *p)
{
PSOCK_BEGIN(p);
PSOCK_SEND_STR(p, "GET /feeds/504.csv HTTP/1.0\r\n");
PSOCK_SEND_STR(p, "User-Agent: econotag\r\n");
PSOCK_SEND_STR(p, "\r\n");
while(1) {
PSOCK_READTO(p, '\n');
printf("Got: %s", buffer);
}
PSOCK_END(p);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_psock_client_process, ev, data)
{
uip_ip6addr_t addr;
PROCESS_BEGIN();
/* Use nginx proxy that is mapping our local
* `::0:82` to `https://api.pachub.com/v2/`
*/
uip_ip6addr(&addr, 0xaaaa,0,0,0,0,0,0,1);
tcp_connect(&addr, UIP_HTONS(82), NULL);
printf("Trying...\n");
PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);
if(uip_aborted() || uip_timedout() || uip_closed()) {
printf("Failed!\n");
} else if(uip_connected()) {
printf("Connected.\n");
PSOCK_INIT(&ps, buffer, sizeof(buffer));
do {
handle_connection(&ps);
PROCESS_WAIT_EVENT_UNTIL(ev == tcpip_event);
} while(!(uip_closed() || uip_aborted() || uip_timedout()));
printf("\nClosed.\n");
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/