Comparing version 0.3.5 to 0.3.6
0.3.6 / 2013-07-11 | ||
================== | ||
* fixed bug in processing query string #13 (@xingrz) | ||
* updated readme example (@xingrz) | ||
* update authors | ||
* API docs (@xingrz) | ||
0.3.5 / 2013-07-10 | ||
@@ -3,0 +11,0 @@ ================== |
@@ -36,3 +36,3 @@ /** | ||
* @example | ||
* | ||
* | ||
* var urllib = require('urllib'); | ||
@@ -44,3 +44,3 @@ * // GET http://httptest.cnodejs.net | ||
* urllib.request('http://httptest.cnodejs.net/test/post', args, function(err, data, res) {}); | ||
* | ||
* | ||
* @param {String|Object} url | ||
@@ -54,3 +54,3 @@ * @param {Object} [args], optional | ||
* We will just `pipe(ws, {end: true})`. | ||
* - {String} [type]: optional, could be GET | POST | DELETE | PUT, default is GET | ||
* - {String} [method]: optional, could be GET | POST | DELETE | PUT, default is GET | ||
* - {String} [dataType]: optional, `text` or `json`, default is text | ||
@@ -73,21 +73,23 @@ * - {Object} [headers]: optional, request headers | ||
} | ||
args = args || {}; | ||
args.timeout = args.timeout || exports.TIMEOUT; | ||
var info = typeof url === 'string' ? urlutil.parse(url) : url; | ||
args.type = (args.type || args.method || info.method || 'GET').toUpperCase(); | ||
var method = args.type; | ||
var port = info.port || 80; | ||
var parsedUrl = typeof url === 'string' ? urlutil.parse(url) : url; | ||
var method = (args.type || args.method || parsedUrl.method || 'GET').toUpperCase(); | ||
var port = parsedUrl.port || 80; | ||
var httplib = http; | ||
var agent = args.agent || exports.agent; | ||
if (info.protocol === 'https:') { | ||
if (parsedUrl.protocol === 'https:') { | ||
httplib = https; | ||
agent = args.httpsAgent || exports.httpsAgent; | ||
if (!info.port) { | ||
if (!parsedUrl.port) { | ||
port = 443; | ||
} | ||
} | ||
var host = info.hostname || info.host || 'localhost'; | ||
var options = { | ||
host: host, | ||
path: info.path || '/', | ||
host: parsedUrl.hostname || parsedUrl.host || 'localhost', | ||
path: parsedUrl.path || '/', | ||
method: method, | ||
@@ -99,3 +101,3 @@ port: port, | ||
var auth = args.auth || info.auth; | ||
var auth = args.auth || parsedUrl.auth; | ||
if (auth) { | ||
@@ -117,6 +119,9 @@ options.auth = auth; | ||
} | ||
// if it's a GET or HEAD request, data should be sent as query string | ||
if ((method === 'GET' || method === 'HEAD') && body) { | ||
options.path += (info.query ? '' : '?') + body; | ||
options.path += (parsedUrl.query ? '&' : '?') + body; | ||
body = null; | ||
} | ||
if (body) { | ||
@@ -129,2 +134,3 @@ var length = body.length; | ||
} | ||
if (args.dataType === 'json') { | ||
@@ -150,9 +156,42 @@ options.headers.Accept = 'application/json'; | ||
// make request | ||
var req = httplib.request(options, function (res) { | ||
if (writeStream) { | ||
// If there's a writable stream to recieve the response data, just pipe the | ||
// response stream to that writable stream and call the callback when it has | ||
// finished writing. | ||
// | ||
// NOTE that when the response stream `res` emits an 'end' event it just | ||
// means that it has finished piping data to another stream. In the | ||
// meanwhile that writable stream may still writing data to the disk until | ||
// it emits a 'close' event. | ||
// | ||
// That means that we should not apply callback until the 'close' of the | ||
// writable stream is emited. | ||
// | ||
// See also: | ||
// - https://github.com/TBEDP/urllib/commit/959ac3365821e0e028c231a5e8efca6af410eabb | ||
// - http://nodejs.org/api/stream.html#stream_event_end | ||
// - http://nodejs.org/api/stream.html#stream_event_close_1 | ||
writeStream.on('close', done.bind(null, null, null, res)); | ||
return res.pipe(writeStream, {end: true}); | ||
return res.pipe(writeStream); | ||
} | ||
// Otherwise, just concat those buffers. | ||
// | ||
// NOTE that the `chunk` is not a String but a Buffer. It means that if | ||
// you simply concat two chunk with `+` you're actually converting both | ||
// Buffers into Strings before concating them. It'll cause problems when | ||
// dealing with multi-byte characters. | ||
// | ||
// The solution is to store each chunk in an array and concat them with | ||
// 'buffer-concat' when all chunks is recieved. | ||
// | ||
// See also: | ||
// http://cnodejs.org/topic/4faf65852e8fb5bc65113403 | ||
var chunks = []; | ||
var size = 0; | ||
res.on('data', function (chunk) { | ||
@@ -162,2 +201,3 @@ size += chunk.length; | ||
}); | ||
res.on('end', function () { | ||
@@ -179,2 +219,3 @@ var data = Buffer.concat(chunks, size); | ||
var __err = null; | ||
timer = setTimeout(function () { | ||
@@ -186,2 +227,3 @@ timer = null; | ||
}, timeout); | ||
req.once('error', function (err) { | ||
@@ -210,3 +252,4 @@ if (!__err && err.name === 'Error') { | ||
} | ||
return req; | ||
}; |
{ | ||
"name": "urllib", | ||
"version": "0.3.5", | ||
"version": "0.3.6", | ||
"description": "Help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, cookies and more.", | ||
@@ -5,0 +5,0 @@ "keywords": [ "urllib", "http", "urlopen", "curl", "wget" ], |
134
README.md
@@ -27,8 +27,90 @@ # urllib [![Build Status](https://secure.travis-ci.org/TBEDP/urllib.png?branch=master)](http://travis-ci.org/TBEDP/urllib) [![Coverage Status](https://coveralls.io/repos/TBEDP/urllib/badge.png)](https://coveralls.io/r/TBEDP/urllib) | ||
### Upload file with [`formstream`](https://github.com/fengmk2/formstream) | ||
## API Doc | ||
### .request(url[, options][, callback][, content]) | ||
#### Arguments | ||
- **url** String | Object - The URL to request, either a String or a Object that return by [url.parse](http://nodejs.org/api/url.html#url_url_parse_urlstr_parsequerystring_slashesdenotehost). | ||
- ***options*** Object - Optional | ||
- ***method*** String - Request method, defaults to `GET`. Could be `GET`, `POST`, `DELETE` or `PUT`. Alias 'type'. | ||
- ***data*** Object - Data to be sent. Will be stringify automatically. | ||
- ***content*** String | [Buffer](http://nodejs.org/api/buffer.html) - Manually set the content of payload. If set, `data` will be ignored. | ||
- ***stream*** [stream.Readable](http://nodejs.org/api/stream.html#stream_class_stream_readable) - Stream to be pipe to the remote. If set, `data` and `content` will be ignored. | ||
- ***writeStream*** [stream.Writable](http://nodejs.org/api/stream.html#stream_class_stream_writable) - A writable stream to be piped by the response stream. Responding data will be write to this stream and `callback` will be called with `data` set `null` after finished writing. | ||
- ***dataType*** String - Type of response data. Could be `text` or `json`. If it's `text`, the `callback`ed `data` would be a Buffer. If it's `json`, the `data` of callback would be a parsed JSON Object. Defaults to `text`. | ||
- ***headers*** Object - Request headers. | ||
- ***timeout*** Number - Request timeout in milliseconds. Defaults to `exports.TIMEOUT`. | ||
- ***auth*** String - `username:password` used in HTTP Basic Authorization. | ||
- ***agent*** [http.Agent](http://nodejs.org/api/http.html#http_class_http_agent) - HTTP Agent object. | ||
- ***httpsAgent*** [https.Agent](http://nodejs.org/api/https.html#https_class_https_agent) - HTTPS Agent object. | ||
- ***callback(err, data, res)*** Function - Optional callback. | ||
- **err** Error - Would be `null` if no error accured. | ||
- **data** Buffer | Object - The data responsed. Would be a Buffer if `dataType` is set to `text` or an JSON parsed into Object if it's set to `json`. | ||
- **res** [stream.Readable](http://nodejs.org/api/stream.html#stream_class_stream_readable) - The response stream. | ||
- ***context*** Object - Optional context object that will be binded to `this` of `callback`. | ||
#### Returns | ||
[stream.Writable](http://nodejs.org/api/stream.html#stream_class_stream_writable) - The request stream. | ||
Calling `.abort()` method of the request stream can cancel the request. | ||
#### `options.data` | ||
When making a request: | ||
```js | ||
urllib.request('http://example.com', { | ||
method: 'GET', | ||
data: { | ||
'a': 'hello', | ||
'b': 'world' | ||
} | ||
}); | ||
``` | ||
For `GET` request, `data` will be stringify to query string, e.g. `http://example.com/?a=hello&world`. | ||
For `POST` or `PUT` request, in defaults, the `data` will be stringify into `application/x-www-form-urlencoded`. | ||
#### `options.content` | ||
`options.content` is useful when you wish to construct the request body by yourself, for example making a `Content-Type: application/json` request. | ||
Notes that if you want to send a JSON body, you should stringify it yourself: | ||
```js | ||
urllib.request('http://example.com', { | ||
method: 'POST', | ||
headers: { | ||
'content-type': 'application/json' | ||
}, | ||
content: JSON.stringify({ | ||
'a': 'hello', | ||
'b': 'world' | ||
}) | ||
}); | ||
``` | ||
It would make a HTTP request like: | ||
```http | ||
POST / HTTP/1.1 | ||
Host: example.com | ||
Content-Type: application/json | ||
{ | ||
"a": "hello", | ||
"b": "world" | ||
} | ||
``` | ||
#### `options.stream` | ||
Uploads a file with [formstream](https://github.com/fengmk2/formstream): | ||
```js | ||
var urllib = require('urllib'); | ||
var formstream = require('formstream'); | ||
var should = require('should'); | ||
@@ -38,18 +120,10 @@ var form = formstream(); | ||
form.field('hello', '你好urllib'); | ||
var args = { | ||
type: 'POST', | ||
var req = urllib.request('http://my.server.com/upload', { | ||
method: 'POST', | ||
headers: form.headers(), | ||
stream: form | ||
}; | ||
var req = urllib.request(host + '/stream', args, function (err, data, res) { | ||
should.not.exist(err); | ||
data = data.toString(); | ||
data.should.include('你好urllib\r\n----------------------------'); | ||
data.should.include('Content-Disposition: form-data; name="file"; filename="urllib.test.js"'); | ||
}, function (err, data) { | ||
// upload finished | ||
}); | ||
// you can abort the request after 5 seconds | ||
setTimout(function () { | ||
req.abort(); | ||
}, 5000); | ||
``` | ||
@@ -59,4 +133,5 @@ | ||
* Upload file like form upload. | ||
* Auto redirect handle. | ||
* [ ] Support component | ||
* [√] Upload file like form upload | ||
* [ ] Auto redirect handle | ||
@@ -71,25 +146,18 @@ ## Authors | ||
project : urllib | ||
repo age : 1 year, 6 months | ||
active : 18 days | ||
commits : 38 | ||
repo age : 2 years, 2 months | ||
active : 28 days | ||
commits : 71 | ||
files : 16 | ||
authors : | ||
33 fengmk2 86.8% | ||
4 Jackson Tian 10.5% | ||
1 aleafs 2.6% | ||
57 fengmk2 80.3% | ||
9 XiNGRZ 12.7% | ||
4 Jackson Tian 5.6% | ||
1 aleafs 1.4% | ||
``` | ||
## Contributors | ||
Ordered by date of first contribution. | ||
[Auto-generated](http://github.com/dtrejo/node-authors) on Tue Aug 14 2012 03:17:14 GMT+0800 (CST). | ||
## License | ||
- [fengmk2](http://fengmk2.github.com) | ||
- [aleafs](https://github.com/aleafs) | ||
- [Jackson Tian aka `JacksonTian`](https://github.com/JacksonTian) | ||
## License | ||
(The MIT License) | ||
Copyright (c) 2011-2012 fengmk2 <fengmk2@gmail.com> | ||
Copyright (c) 2011-2013 fengmk2 <fengmk2@gmail.com> | ||
@@ -96,0 +164,0 @@ Permission is hereby granted, free of charge, to any person obtaining |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
17615
213
178
0