diff --git a/META.json b/META.json index 3c9a960..990d9a6 100644 --- a/META.json +++ b/META.json @@ -2,7 +2,7 @@ "name": "http", "abstract": "HTTP client for PostgreSQL", "description": "HTTP allows you to get the content of a web page in a SQL function call.", - "version": "1.1", + "version": "1.2", "maintainer": [ "Paul Ramsey " ], @@ -21,9 +21,9 @@ }, "provides": { "http": { - "file": "http--1.1.sql", + "file": "http--1.2.sql", "docfile": "README.md", - "version": "1.1", + "version": "1.2", "abstract": "HTTP client for PostgreSQL" }, }, diff --git a/Makefile b/Makefile index f70b041..bccf427 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ MODULE_big = http OBJS = http.o EXTENSION = http -DATA = http--1.1.sql http--1.0--1.1.sql +DATA = http--1.2.sql http--1.1--1.2.sql http--1.0--1.1.sql REGRESS = http EXTRA_CLEAN = diff --git a/README.md b/README.md index 870cccb..fd1e9cd 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,22 @@ To access binary content, you must coerce the content from the default `varchar` --------------+---------------+---------------- image/gif | 31958 | 31958 +To access only the headers you can do a HEAD-Request. This will not follow redirections. + + SELECT + http.status, + headers.value AS location + FROM + http_head('http://google.com') AS http + LEFT OUTER JOIN LATERAL (SELECT value + FROM unnest(http.headers) + WHERE field = 'Location') AS headers + ON true; + + status | location + --------+----------------------------------------------------------- + 302 | http://www.google.ch/?gfe_rd=cr&ei=ACESWLy_KuvI8zeghL64Ag + ## Concepts Every HTTP call is a made up of an `http_request` and an `http_response`. @@ -144,7 +160,7 @@ Every HTTP call is a made up of an `http_request` and an `http_response`. headers | http_header[] | content | character varying | -The utility functions, `http_get()`, `http_post()`, `http_put()`, and `http_delete()` are just wrappers around a master function, `http(http_request)` that returns `http_response`. +The utility functions, `http_get()`, `http_post()`, `http_put()`, `http_delete()` and `http_head()` are just wrappers around a master function, `http(http_request)` that returns `http_response`. The `headers` field for requests and response is a PostgreSQL array of type `http_header` which is just a simple tuple. @@ -178,6 +194,7 @@ By default a 5 second timeout is set for the completion of a request. If a diff * `http_post(uri VARCHAR, content VARCHAR, content_type VARCHAR)` returns `http_response` * `http_put(uri VARCHAR, content VARCHAR, content_type VARCHAR)` returns `http_response` * `http_delete(uri VARCHAR)` returns `http_resonse` +* `http_head(uri VARCHAR)` returns `http_resonse` * `urlencode(string VARCHAR)` returns `text` ## Installation diff --git a/http--1.1--1.2.sql b/http--1.1--1.2.sql new file mode 100644 index 0000000..6c8b1fd --- /dev/null +++ b/http--1.1--1.2.sql @@ -0,0 +1,14 @@ + +ALTER DOMAIN http_method DROP CONSTRAINT http_method_check; +ALTER DOMAIN http_method ADD CHECK ( + VALUE ILIKE 'get' OR + VALUE ILIKE 'post' OR + VALUE ILIKE 'put' OR + VALUE ILIKE 'delete' OR + VALUE ILIKE 'head' +); + +CREATE OR REPLACE FUNCTION http_head(uri VARCHAR) + RETURNS http_response + AS $$ SELECT http(('HEAD', $1, NULL, NULL, NULL)::http_request) $$ + LANGUAGE 'sql'; diff --git a/http--1.1.sql b/http--1.2.sql similarity index 89% rename from http--1.1.sql rename to http--1.2.sql index 603d4fb..f1f408e 100644 --- a/http--1.1.sql +++ b/http--1.2.sql @@ -6,7 +6,8 @@ CHECK ( VALUE ILIKE 'get' OR VALUE ILIKE 'post' OR VALUE ILIKE 'put' OR - VALUE ILIKE 'delete' + VALUE ILIKE 'delete' OR + VALUE ILIKE 'head' ); CREATE DOMAIN content_type AS text @@ -63,6 +64,11 @@ CREATE OR REPLACE FUNCTION http_delete(uri VARCHAR) RETURNS http_response AS $$ SELECT http(('DELETE', $1, NULL, NULL, NULL)::http_request) $$ LANGUAGE 'sql'; + +CREATE OR REPLACE FUNCTION http_head(uri VARCHAR) + RETURNS http_response + AS $$ SELECT http(('HEAD', $1, NULL, NULL, NULL)::http_request) $$ + LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION urlencode(string VARCHAR) RETURNS TEXT diff --git a/http.c b/http.c index ec0f8b4..3226faa 100644 --- a/http.c +++ b/http.c @@ -70,7 +70,8 @@ typedef enum { HTTP_GET, HTTP_POST, HTTP_DELETE, - HTTP_PUT + HTTP_PUT, + HTTP_HEAD } http_method; /* Components (and postitions) of the http_request tuple type */ @@ -213,6 +214,8 @@ request_type(const char *method) return HTTP_PUT; else if ( strcasecmp(method, "DELETE") == 0 ) return HTTP_DELETE; + else if ( strcasecmp(method, "HEAD") == 0 ) + return HTTP_HEAD; else return HTTP_GET; } @@ -604,10 +607,13 @@ Datum http_request(PG_FUNCTION_ARGS) /* Set the HTTP content encoding to gzip */ /*curl_easy_setopt(g_http_handle, CURLOPT_ACCEPT_ENCODING, HTTP_ENCODING);*/ - /* Follow redirects, as many as 5 */ - CURL_SETOPT(g_http_handle, CURLOPT_FOLLOWLOCATION, 1); - CURL_SETOPT(g_http_handle, CURLOPT_MAXREDIRS, 5); - + if ( method != HTTP_HEAD ) + { + /* Follow redirects, as many as 5 */ + CURL_SETOPT(g_http_handle, CURLOPT_FOLLOWLOCATION, 1); + CURL_SETOPT(g_http_handle, CURLOPT_MAXREDIRS, 5); + } + if ( g_use_keepalive ) { /* Add a keep alive option to the headers to reuse network sockets */ @@ -678,6 +684,10 @@ Datum http_request(PG_FUNCTION_ARGS) { CURL_SETOPT(g_http_handle, CURLOPT_CUSTOMREQUEST, "DELETE"); } + else if ( method == HTTP_HEAD ) + { + CURL_SETOPT(g_http_handle, CURLOPT_NOBODY, 1); + } /* Set the headers */ CURL_SETOPT(g_http_handle, CURLOPT_HTTPHEADER, headers); diff --git a/http.control b/http.control index 942e687..5270225 100644 --- a/http.control +++ b/http.control @@ -1,4 +1,4 @@ -default_version = '1.1' +default_version = '1.2' module_pathname = '$libdir/http' relocatable = true comment = 'HTTP client for PostgreSQL, allows web page retrieval inside the database.'