request.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * Utilities: A classic collection of JavaScript utilities
  3. * Copyright 2112 Matthew Eernisse ([email protected])
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. var http = require('http')
  19. , https = require('https')
  20. , url = require('url')
  21. , uri = require('./uri')
  22. , log = require('./log')
  23. , core = require('./core');
  24. /**
  25. @name request
  26. @namespace request
  27. @public
  28. @function
  29. @description Sends requests to the given url sending any data if the method is POST or PUT
  30. @param {Object} opts The options to use for the request
  31. @param {String} [opts.url] The URL to send the request to
  32. @param {String} [opts.method=GET] The method to use for the request
  33. @param {Object} [opts.headers] Headers to send on requests
  34. @param {String} [opts.data] Data to send on POST and PUT requests
  35. @param {String} [opts.dataType] The type of data to send
  36. @param {Function} callback the function to call after, args are `error, data`
  37. */
  38. var request = function (opts, callback) {
  39. var client
  40. , options = opts || {}
  41. , parsed = url.parse(options.url)
  42. , path
  43. , requester = parsed.protocol == 'http:' ? http : https
  44. , method = (options.method && options.method.toUpperCase()) || 'GET'
  45. , headers = core.mixin({}, options.headers || {})
  46. , data = options.data
  47. , contentLength
  48. , port
  49. , clientOpts;
  50. if (parsed.port) {
  51. port = parsed.port;
  52. }
  53. else {
  54. port = parsed.protocol == 'http:' ? '80' : '443';
  55. }
  56. path = parsed.pathname;
  57. if (method == 'POST' || method == 'PUT') {
  58. // Handle the payload and content-length
  59. if (data) {
  60. // JSON data
  61. if (options.dataType == 'json') {
  62. if (typeof data == 'object') {
  63. data = JSON.stringify(data);
  64. }
  65. headers['Content-Type'] = headers['Content-Type'] ||
  66. headers['content-type'] || 'application/json';
  67. }
  68. // Form data
  69. else {
  70. if (typeof data == 'object') {
  71. data = uri.paramify(data);
  72. }
  73. // FIXME: What is the prefix for form-urlencoded?
  74. headers['Content-Type'] = headers['Content-Type'] ||
  75. headers['content-type'] || 'form-urlencoded';
  76. }
  77. contentLength = Buffer.byteLength(data);
  78. }
  79. else {
  80. contentLength = 0
  81. }
  82. headers['Content-Length'] = contentLength;
  83. if (parsed.search) {
  84. path += parsed.search;
  85. }
  86. }
  87. else {
  88. if (data) {
  89. // Data is an object, parse into querystring
  90. if (typeof data == 'object') {
  91. data = uri.paramify(data);
  92. }
  93. // Create querystring or append to existing
  94. if (parsed.search) {
  95. path += parsed.search; // search includes question mark
  96. path += '&' + data;
  97. }
  98. else {
  99. path += '?' + data;
  100. }
  101. }
  102. }
  103. clientOpts = {
  104. host: parsed.hostname
  105. , port: port
  106. , method: method
  107. , agent: false
  108. , path: path
  109. , headers: headers
  110. };
  111. client = requester.request(clientOpts);
  112. client.addListener('response', function (resp) {
  113. var data = '';
  114. resp.addListener('data', function (chunk) {
  115. data += chunk.toString();
  116. });
  117. resp.addListener('end', function () {
  118. var stat = resp.statusCode
  119. , contentType
  120. , err;
  121. // Successful response
  122. if ((stat > 199 && stat < 300) || stat == 304) {
  123. if (data) {
  124. contentType = resp.headers['Content-Type'];
  125. if (contentType == 'application/json' || contentType == 'text/json' ||
  126. uri.getFileExtension(parsed.pathname) == 'json') {
  127. try {
  128. data = JSON.parse(data);
  129. }
  130. catch (e) {
  131. return callback(e, null);
  132. }
  133. }
  134. callback(null, data);
  135. }
  136. else {
  137. callback(null, null);
  138. }
  139. }
  140. // Something failed
  141. else {
  142. err = new Error(data);
  143. err.statusCode = resp.statusCode;
  144. callback(err, null);
  145. }
  146. });
  147. });
  148. client.addListener('error', function (e) {
  149. callback(e, null);
  150. });
  151. if ((method == 'POST' || method == 'PUT') && data) {
  152. client.write(data);
  153. }
  154. client.end();
  155. };
  156. module.exports = request;