Hi,
I have written a JS-Class that allows sending http-requests and retrieve / parse the responses.
It uses the socket()-class.
It supports:
- get the Status-Code of a webresource
- fetch the headers of a webresource
- return the data of a webresource as string
- save the data into a local file and return a File()-Object of it
- Basic Authentication of webresources
- Use of Proxy-Server
- Authentication of Proxy-Server
- following Redirections in a controlled manner
- ...
It doesn't support:
- HTTPS
- POST-Requests (only GET / HEAD)
the use is very simple and easy:
Code: Select all// creating the Object
var http = new HN_http_request();
// set the url
http.set_url('http://example.com/path/to/resource.typ');
// set the request_type
http.set_request_type('only_status');
// get the result
var result = http.get_result();
alert( result==false ? http.get_error() : result );
// -------------------------------------------------------
// setup:
// the different request_types are:
http.set_request_type('only_status');
http.set_request_type('only_headers');
http.set_request_type('data');
http.set_request_type('data', local_filename);
// controlling Redirections
http.set_max_redirections(4);
// setting the URI is also used to pass data for Non-Standard-Ports, Authorization, Query,
// Proxy, Proxy-Port, Proxy-Authorization, all at once:
http.set_url('http://example.com/path/to/resource.typ');
http.set_url('http://example.com:8080/path/to/resource.typ');
http.set_url('http://example.com/path/to/resource.typ ... &var2=val2');
http.set_url('http://user:password@example.com/path/to/resource.typ');
http.set_url('http://example.com/path/to/resource.typ', 'http://proxyhost.test');
http.set_url('http://example.com/path/to/resource.typ', 'http://proxyhost.test:3128');
http.set_url('http://example.com/path/to/resource.typ', 'http://proxyuser:proxypassword@proxyhost.test:3128');
// get result:
// save webresource to local file
http.set_request_type('data', local_filename);
var myFile = http.get_result();
// check value of specific Header:
http.get_response_header('status-code');
http.get_response_header('reason-phrase');
http.get_response_header('content-type');
http.get_response_header('content-length');
http.get_response_header('last-modified');
here is the script content with demos / examples:
(you also can download it as plaintext-file here: http://nogajski.de/download/?f=hn_http_request.jsx)
Code: Select all/*
Photoshop-Script: hn_http_request.jsx
Allows to fetch HTTP-Resources or their Informations in many ways,
comfortable and easy. See and run the demos at the end of the file.
@Author: Horst Nogajski <info [AT] nogajski [DOT] de>
@Version: 1.0
@Date: 2010/07/04
@Licence: MIT
$Source: /JSX/libs/hn_http_request.jsx,v $
$Id: hn_http_request.jsx,v 1.2 2010/07/04 22:31:06 horst Exp $
CREDITS:
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
*/
/* HN_http_request */
try
{
/* constructor */
function HN_http_request()
{
try {
// class-vars for setters
this.sRequestType = 'data'; // 'only_status' | 'only_headers' | 'data'
this.sLocalFilename = null;
this.iMaxRedirections = 4;
// class-vars for getters
this.sStatuscode = null;
this.sReasonPhrase = null;
this.sRequest = null;
this.sResponse = null;
this.sError = '';
// private other class-vars
this.sKeptProxyUrl = null;
this.bUseProxy = false;
this.sProxyHost = null;
this.iProxyPort = null;
this.sProxyAuthHeader = null;
this.sUriHost = null;
this.sUriPath = null;
this.iUriPort = 80;
this.sAuthorizationHeader = null;
this.sRefererHeader = null;
this.sCookieHeader = null;
this.iRedirections = 0;
this.oResponse = new Object();
this.oSocket = new Socket();
}
catch(e) { alert("ERROR:\n" + e); }
}
/* SETTERS */
/* set_url(sUrl) */
HN_http_request.prototype.set_url = function(url, proxy_url)
{
try
{
if(!url.match(/:\/\//))
{
url = 'http://' + url;
}
var URI = parseUri(url);
if(URI.protocol.toLowerCase() != "http")
{
this.sError = "URL-scheme isn't supported:\n" + URI.protocol;
return false;
}
this.sUriHost = URI.host;
this.iUriPort = (URI.port == '') ? 80 : URI.port;
this.sUriPath = (URI.path == '') ? '/' : URI.path;
this.sUriPath += (URI.query == '') ? '' : '?' + URI.query;
this.sUriPath += (URI.anchor == '') ? '' : '#' + URI.anchor;
if(URI.user != '' && URI.password != '' && URI.source.match(/.*?:.*?@.*/))
{
this.sAuthorizationHeader = 'Authorization: Basic ' + this._base64_encode(URI.user + ':' + URI.password) + "\r\n";
}
//alert(URI.host + "\n" + URI.port + "\n" + URI.path + "\n" + URI.query + "\n" + URI.anchor + "\n" + URI.user + "\n" + URI.password);
//alert(this.sUriHost + "\n" + this.iUriPort + "\n" + this.sUriPath + "\n" + this.sAuthorizationHeader);
this.sKeptProxyUrl = proxy_url;
this.bUseProxy = (typeof proxy_url=='undefined' || proxy_url=='' || proxy_url==null) ? false : true;
if(this.bUseProxy)
{
// setup the proxy params
if(!proxy_url.match(/:\/\//))
{
proxy_url = 'http://' + proxy_url;
}
var PROXY = parseUri(proxy_url);
this.sProxyHost = PROXY.host;
this.iProxyPort = (PROXY.port == '') ? 80 : PROXY.port;
if(PROXY.user != '' && PROXY.password != '' && PROXY.source.match(/.*?:.*?@.*/))
{
this.sProxyAuthHeader = 'Proxy-Authorization: Basic ' + this._base64_encode(PROXY.user + ':' + PROXY.password) + "\r\n";
}
}
return true;
}
catch(e) { alert("ERROR:\n" + e); }
}
/* set_request_type(sRequestType) */
//
// valid params: [ 'only_status' | 'only_headers' | 'data' ] , optional (when using 'data') a local_filename
// default: 'data'
HN_http_request.prototype.set_request_type = function(value, local_filename)
{
try
{
this.sError = '';
this.sLocalFilename = null;
this.sStatuscode = null;
this.sRequest = null;
this.sResponse = null;
this.oResponse = new Object();
this.oSocket = new Socket();
if(value.toLowerCase() == 'only_status')
{
this.sRequestType = 'only_status';
}
else if(value.toLowerCase() == 'only_headers')
{
this.sRequestType = 'only_headers';
}
else
{
if(typeof local_filename == 'undefined' || local_filename == null || local_filename == '')
{
this.sRequestType = 'DATA_STRING';
}
else
{
this.sRequestType = 'DATA_FILE';
this.sLocalFilename = local_filename;
}
}
}
catch(e) { alert("ERROR:\n" + e); }
}
/* set_max_redirections(iMaxRedirections) */
//
HN_http_request.prototype.set_max_redirections = function(value) { this.iMaxRedirections = value; }
/* GETTERS */
/* get_statuscode() */
//
HN_http_request.prototype.get_statuscode = function() { return this.sStatuscode; }
/* get_request() */
//
HN_http_request.prototype.get_request = function() { return this.sRequest; }
/* get_response_allheaders() */
//
HN_http_request.prototype.get_response_allheaders = function() { return this.sResponse; }
/* get_response_header(headername) */
//
HN_http_request.prototype.get_response_header = function(headername)
{
try {
for(var key in this.oResponse)
{
if(key == headername.toLowerCase())
{
return this.oResponse[key];
}
}
return null;
}
catch(e) { alert("ERROR:\n" + e); }
}
/* get_error() */
//
HN_http_request.prototype.get_error = function()
{
try {
var sInfo = "---[HN_http_request]-----------------------------------------------\n";
if(this.bUseProxy==true)
{
sInfo += " - proxy_host: " + this.sProxyHost + "\n";
sInfo += " - proxy_port: " + this.iProxyPort + "\n";
}
sInfo += " - uri_host: " + this.sUriHost + "\n";
sInfo += " - uri_port: " + this.iUriPort + "\n";
sInfo += " - uri_path: " + this.sUriPath + "\n";
sInfo += " - request_type: " + this.sRequestType + "\n";
sInfo += " - status-code: " + this.sStatuscode + "\n";
sInfo += " - reason-phrase: " + this.sReasonPhrase + "\n\n";
sInfo += "---[ERROR:]--------------------------------------------------------\n";
return sInfo + this.sError;
}
catch(e) { alert("ERROR:\n" + e); }
}
/* get_result(bIsRedirected) */
//
HN_http_request.prototype.get_result = function(bIsRedirected)
{
try {
var buffer = '';
var dump = '';
var dataoffset = null;
var a = null;
var key = null;
// optional reset some vars
if(typeof bIsRedirected=='undefined' || bIsRedirected!=true)
{
this.iRedirections = 0;
}
// build HTTP-Request:
var myConnection = this.sUriHost + ':' + this.iUriPort;
var myRequest = this.sRequestType=='only_status' ? "HEAD " : "GET ";
myRequest += this.sUriPath + " HTTP/1.1\r\n";
if(this.bUseProxy==true)
{
myConnection = this.sProxyHost + ':' + this.iProxyPort;
myRequest = this.sRequestType=='only_status' ? "HEAD " : "GET ";
myRequest += 'http://' + this.sUriHost + ':' + this.iUriPort + this.sUriPath + " HTTP/1.1\r\n";
myRequest += (this.sProxyAuthHeader==null) ? '' : this.sProxyAuthHeader;
myRequest += "Proxy-Connection: close\r\n";
}
myRequest += "Host: " + this.sUriHost + "\r\n";
myRequest += (this.sAuthorizationHeader==null) ? '' : this.sAuthorizationHeader;
myRequest += (this.sRefererHeader==null) ? '' : "Referer: " + this.sRefererHeader + "\r\n";
myRequest += (this.sCookieHeader==null) ? '' : "Cookie: " + this.sCookieHeader + "\r\n";
myRequest += "User-Agent: ESTK/" + $.version + " (" + $.os + ")\r\n";
myRequest += "Pragma: no-cache\r\n";
myRequest += "Cache-Control: no-cache\r\n";
myRequest += "Cache-Control: max-age=0\r\n";
myRequest += "Cache-Control: max-stale=0\r\n";
myRequest += "Connection: close\r\n\r\n";
this.sRequest = myConnection + "\n\n" + myRequest;
// connect to host or proxy
if(!this.oSocket.open(myConnection, "binary"))
{
this.sError = "Cannot open Socket:\n" + myConnection;
return false;
}
// send request and read a first chunk on the wire
this.oSocket.write(myRequest);
this.sRefererHeader = 'http://' + this.sUriHost + ':' + this.iUriPort + this.sUriPath;
buffer = this.oSocket.read(1536);
// parse all headers
var lines = buffer.split("\r\n");
dump = '';
for(var line in lines)
{
// get the status-code from HTTP-Headerline
if(lines[line].substr(0,7)=='HTTP/1.')
{
this.sStatuscode = lines[line].substr(9,3);
this.sReasonPhrase = lines[line].substr(13);
this.oResponse['status-code'] = this.sStatuscode;
this.oResponse['reason-phrase'] = this.sReasonPhrase;
// CHECK-OUT for ONLY_STATUS
if(this.sRequestType=='only_status')
{
// early checkout
this.oSocket.close();
return this.sStatuscode;
}
dump += lines[line] + "\r\n";
continue;
}
if(lines[line] == "")
{
// empty header-line = headers end & data starts
this.sResponse = dump;
this.dataoffset = dump.length + 2;
break;
}
// alle weiteren headerzeilen werden geparst und in key / value aufgeteilt
dump += lines[line] + "\r\n";
a = lines[line].split(': ');
key = a[0].toLowerCase();
a.shift();
this.oResponse[key] = a.join(': ');
if(key=='set-cookie')
{
this.sCookieHeader = a.join(': ');
}
}
// checking Status-Code for Redirections
if(this.sStatuscode[0]=='3' && this.iRedirections < this.iMaxRedirections)
{
this.oSocket.close();
this.iRedirections++;
var current_host = this.sUriHost;
var new_location = this.get_response_header('location');
if(new_location==false || new_location==null)
{
this.sError = "StatusCode is [" + this.sStatuscode + "], but we haven't found a Location-Header!\n\nnew_location = " + new_location + "\nRedirections = " + this.sRedirections;
return false;
}
if(new_location.substr(0,7)!='http://')
{
new_location = 'http://' + current_host + new_location;
}
this.set_url(new_location, this.sKeptProxyUrl);
return this.get_result(true);
}
// final Check of Status-Code
if(this.sStatuscode!='200')
{
this.oSocket.close();
if(this.sStatuscode[0]=='3')
{
this.sError = "To much Redirections!\nRedirections = " + this.iRedirections;
}
else
{
this.sError = "Not the right StatusCode: [" + this.sStatuscode + "]\n\nRedirections = " + this.iRedirections;
}
return false;
}
// CHECK-OUT for HEADERS_ONLY
if(this.sRequestType=='only_headers')
{
this.oSocket.close();
return this.sRequest + "\n" + this.sResponse;
}
// CHECK-OUT for DATA_STRING
if(this.sRequestType=='DATA_STRING')
{
// den Rest des buffers in filecontent zuweisen
var filecontent = buffer.substr(this.dataoffset);
while(!this.oSocket.eof)
{
filecontent += this.oSocket.read(4096);
}
this.oSocket.close();
return filecontent;
}
// CHECK-OUT for DATA_FILE
if(this.sRequestType=='DATA_FILE' && this.sLocalFilename!=null)
{
var f = new File(this.sLocalFilename);
f.encoding = "binary";
if(!f.open('w'))
{
this.oSocket.close();
this.sError = "Cannot open file for writing:\n" + this.sLocalFilename;
return false;
}
f.write(buffer.substr(this.dataoffset));
while(!this.oSocket.eof)
{
f.write(this.oSocket.read(4096));
}
f.close();
this.oSocket.close();
return f;
}
// should never be reached, this line, ...
this.sError = "Seems to be, that there wasn't set a right RequestType!";
return false;
}
catch(e) { alert("ERROR:\n" + e); }
}
/* HELPERS */
/* _base64_encode(sInput) */
//
HN_http_request.prototype._base64_encode = function(sInput)
{
try
{
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
var output = '';
while(i < sInput.length)
{
chr1 = sInput.charCodeAt(i++);
chr2 = sInput.charCodeAt(i++);
chr3 = sInput.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if(isNaN(chr2))
{
enc3 = enc4 = 64;
}
else if(isNaN(chr3))
{
enc4 = 64;
}
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
}
return output;
}
catch(e) { alert("ERROR:\n" + e); }
}
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
function parseUri (str)
{
try
{
var o = parseUri.options,
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
uri = {},
i = 14;
while (i--) uri[o.key] = m || "";
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) uri[o.q.name][$1] = $2;
});
return uri;
}
catch(e) { alert("ERROR:\n" + e); }
}
parseUri.options = {
strictMode: false,
key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
}
};
// EXAMPLES:
if(confirm('Do you want to run Demos of the http_request-class?'))
{
var result = null;
// creating the Object
var http = new HN_http_request();
// A)
// a short and simple HEAD-Request, to get the status code of a web resource
// returns: string = StatusCode, e.g. 200 | 404 | 304 | 501 | ...
// or false on failure
alert("The first Demo try to fetch the Status-Code of a webresource:\n\n if(!http.set_url('http://nogajski.de/autosoftproof_doc_en/'))\n {\n alert(http.get_error());\n }\n else\n {\n http.set_request_type('only_status');\n result = http.get_result();\n alert( result==false ? http.get_error() : result );\n }\n");
// set the url
if(!http.set_url('http://nogajski.de/autosoftproof_doc_en/'))
{
alert(http.get_error());
}
else
{
http.set_request_type('only_status');
result = http.get_result();
alert( result==false ? http.get_error() : result );
}
// B)
// fetch all headers as dump and as Object
if(confirm("The second Demo fetches all Response-Headers:\n\n if(!http.set_url('http://nogajski.de/autosoftproof_doc_en/'))\n {\n alert(http.get_error());\n }\n else\n {\n http.set_request_type('only_headers');\n result = http.get_result();\n alert( result==false ? \"Fetching headers fails: \" + http.get_error() : result );\n\n result = http.get_response_header('status-code');\n alert( result==false ? \"Fetching a single header fails: \" + http.get_error() : \"status-code = \" + result );\n\n result = http.get_response_header('reason-phrase');\n alert( result==false ? \"Fetching a single header fails: \" + http.get_error() : \"reason-phrase = \" + result );\n\n result = http.get_response_header('content-length');\n alert( result==false ? \"Fetching a single header fails: \" + http.get_error() : \"content-length = \" + result );\n }\n\n\nDo you want to run it now?"))
{
// set the url
if(!http.set_url('http://nogajski.de/autosoftproof_doc_en/'))
{
alert(http.get_error());
}
else
{
http.set_request_type('only_headers');
result = http.get_result();
alert( result==false ? "Fetching headers fails:\n\n" + http.get_error() : result );
// C)
// looking for specific Headers
// when the request_type isn't "only_status", you don't need to execute http.get_result() again,
// because all headers are fetched and kept in the class. You simply check the header:
result = http.get_response_header('status-code');
alert( result==false ? "Fetching a single header fails:\n\n" + http.get_error() : "status-code = " + result );
result = http.get_response_header('reason-phrase');
alert( result==false ? "Fetching a single header fails:\n\n" + http.get_error() : "reason-phrase = " + result );
result = http.get_response_header('content-length');
alert( result==false ? "Fetching a single header fails:\n\n" + http.get_error() : "content-length = " + result );
result = http.get_response_header('last-modified');
alert( result==false ? "Fetching a single header fails:\n\n" + http.get_error() : "last-modified = " + result );
result = http.get_response_header('content-type');
alert( result==false ? "Fetching a single header fails:\n\n" + http.get_error() : "content-type = " + result );
result = http.get_response_header('thisheader-shouldnot-exist');
alert( result==false ? "Fetching a single header fails:\n\n" + http.get_error() : "thisheader-shouldnot-exist = " + result );
}
}
// D)
// follow Redirections in a controlled manner
if(confirm("Next part demonstrates the ability to follow Redirections in a controlled manner:\n\nDo you want to run it now?"))
{
// set the url
if(!http.set_url('http://nogajski.de/redir'))
{
alert(http.get_error());
}
else
{
http.set_request_type('only_headers');
result = http.get_result();
alert( result==false ? "Fetching headers fails:\n\n" + http.get_error() : result );
alert("Now, we increase the number of allowed Redirections from the default of 4 to 8, and try again!\n\n http.set_max_redirections(8);\n");
http.set_max_redirections(8);
result = http.get_result();
alert( result==false ? "Fetching headers fails:\n\n" + http.get_error() : result );
}
}
// E)
// when passing 'data' as type and a local-filename as second param, it downloads the web resource into a local file
// returns a File()-Object
// or false on failure
// F)
// when passing 'data' as type _without_ the optional second param local-filename, the downloaded content is returned as string:
// http.set_request_type('data');
var local_filename = $.getenv('TEMP');
local_filename = Folder(local_filename).exists ? local_filename : $.getenv('TMP');
local_filename = Folder(local_filename).exists ? local_filename + '/downloaded.pdf' : null;
var myQuestion = local_filename==null ? "Last Demo download a Resource and returns it as a string!\nBut you also can save it directly into a local file.\n\n" : "Last Demo try to download a Resource and save it into:\n - [" + local_filename + "] - \n\n";
if(confirm(myQuestion + " if(local_filename==null)\n {\n http.set_url('http://nogajski.de/autosoftproof_doc_en/')\n http.set_request_type('data');\n result = http.get_result();\n alert( result==false ? \"Fetching data fails: \" + http.get_error() : result );\n }\n else\n {\n http.set_url('http://nogajski.de/autosoftproof_doc_en/')\n http.set_request_type('data', local_filename);\n var myFile = http.get_result();\n if(myFile instanceof Object)\n {\n if(myFile.exists)\n {\n myFile.execute();\n }\n }\n }\n\nDo you want to run it now?"))
{
if(local_filename==null)
{
http.set_url('http://nogajski.de/autosoftproof_doc_en/')
http.set_request_type('data');
result = http.get_result();
alert( result==false ? "Fetching data fails:\n\n" + http.get_error() : result );
}
else
{
http.set_url('http://nogajski.de/autosoftproof_doc_en/')
http.set_request_type('data', local_filename);
var myFile = http.get_result();
if(myFile instanceof Object)
{
if(myFile.exists)
{
myFile.execute();
}
}
}
}
}
}
catch(e) { alert("ERROR:\n" + e); }
Best regards,
Biriba