Skip to content

Configuring HTTP Proxy

Benoît Thébaudeau edited this page Sep 23, 2019 · 12 revisions

Example 1: Using HTTPS API (with trimmed headers & shorter URL)

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 allow it only on the local network ...

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 (or care about provisioning)
  • shorten the URL suffix or rewrite it for your needs

... and even:

  • take care about provisioning, but instead only provision the proxy app instance but not avoid provisioning each node (TODO)

Header optimisation

The idea is to avoid transfer of unnecessary information via the 6loWPAN segment.

It appears that Cosm server (api.cosm.com) sends the following response headers:

  % curl -6 https://api.cosm.com/v2/feeds/61916.csv -v
  * About to connect() to localhost port 82 (#0)
  *   Trying ::1... connected
  * Connected to localhost (::1) port 82 (#0)
  > GET /feeds/61916.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

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

Proxied Cosm API example

This is multi-port configuration, hopefully it is quite self-explanatory.

user nginx nginx; worker_processes 3;

error_log log/nginx/cosm-ssl-proxy.err debug;

events {
 worker_connections 1024;
 use epoll;
}

http {
 upstream cosm-ssl-proxy {
   ## see: http://cosm.com/docs/v2/ip_addresses.html
   #server 173.203.98.29:443;
   server api.cosm.com:443;
 }
 server {
   # curl https://api.cosm.com/v2/feeds/504.csv
   # curl -6 http://localhost/feeds/504.csv
   listen [::0]:80;
   location / {
     proxy_set_header host api.cosm.com;
     proxy_set_header X-ApiKey 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 X-RequestId;
     proxy_hide_header Cache-Control;
     proxy_pass https://cosm-ssl-proxy/v2/;
   }
 }
}

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, "Cosm 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();
}
/*---------------------------------------------------------------------------*/
Clone this wiki locally