Documentationcurrent version
Help us improve the docs by fixing typos and proposing enhancements.

Nikita

Action "network.http"

Perform an HTTP request. Internaly, the action requires the presence of the curl command.

Return

  • data (string)
    The decoded data is type is provided or detected.
  • body (string)
    The HTTP response body.
  • headers ([string])
    The HTTP response headers.
  • http_version ([string])
    The HTTP response http_version, eg 'HTTP/1.1'.
  • status_code (string)
    The HTTP response status code.
  • status_message (string)
    The HTTP response status message.
  • type (string)
    The format type if provided or detected, possible values is only "json" for now.

Error

The error.code reflects the native curl errors code. You can get a list of them with man 3 libcurl-errors. For example:

try {
  await nikita.network.http({
    url: "http://2222:localhost"
  })
} catch (err) {
  assert(err.code, 'CURLE_URL_MALFORMAT')
  assert(err.message, 'CURLE_URL_MALFORMAT: the curl command exited with code `3`.')
}

Schema definitions

definitions =
  config:
    type: 'object'
    properties:
      'cookies':
        type: 'array'
        items:
          type: 'string'
        description: '''
        Extra cookies to include in the request when sending HTTP to a server.
        '''
      'data':
        type: ['array', 'boolean', 'null', 'number', 'object', 'string']
        description: '''
        The request HTTP body associated with "POST" and "PUT" requests. The
        `Accept: application/json` request header will be automatically
        inserted if not yet present and if `data` is not a string.
        '''
      'fail':
        type: 'boolean'
        description: '''
        Fail silently (no output at all) on HTTP errors.
        '''
      'gid':
        $ref: 'module://@nikitajs/core/lib/actions/fs/chown#/definitions/config/properties/gid'
        description: '''
        Group name or id who owns the target file; only apply if `target` is
        provided.
        '''
      'http_headers':
        type: 'object'
        default: {}
        description: '''
        Extra header to include in the request when sending the HTTP request
        to a server.
        '''
      'insecure':
        type: 'boolean'
        description: '''
        Allow insecure server connections when using SSL; disabled if `cacert`
        is provided.
        '''
      'location':
        type: 'boolean'
        description: '''
        If the server reports that the requested page has moved to a different
        location (indicated with a Location: header and a 3XX response code),
        this option will make curl redo the request on the new place.
        '''
      'method':
        type: 'string'
        default: 'GET'
        description: '''
        Specify request command (HTTP method) to use.
        '''
      'mode':
        $ref: 'module://@nikitajs/core/lib/actions/fs/chmod#/definitions/config/properties/mode'
        description: '''
        Permissions of the target. If specified, nikita will chmod after
        download.
        '''
      'negotiate':
        type: 'boolean'
        description: '''
        Use HTTP Negotiate (SPNEGO) authentication.
        '''
      'proxy':
        type: 'string'
        description: '''
        Use the specified HTTP proxy. If the port number is not specified, it
        is assumed at port 1080. See curl(1) man page.
        '''
      'password':
        type: 'string'
        description: '''
        Password associated with the Kerberos principal, required if
        `principal` is provided.
        '''
      'principal':
        type: 'string'
        description: '''
        Kerberos principal name if a ticket must be generated along the
        `negociate` option.
        '''
      'referer':
        type: 'string'
        description: '''
        An alias for connection.http_headers[\'Referer\']
        '''
      'target':
        type: 'string'
        description: '''
        Write to file instead of stdout; mapped to the curl `output` argument.
        '''
      'timeout':
        $ref: 'module://@nikitajs/network/src/tcp/wait#/definitions/config/properties/timeout'
        description: '''
        Maximum time in millisecond for the HTTP request. Prevent the
        request from hanging.
        '''
      'uid':
        $ref: 'module://@nikitajs/core/lib/actions/fs/chown#/definitions/config/properties/uid'
        description: '''
        User name or id who owns the target file; only apply if `target` is
        provided.
        '''
      'url':
        type: 'string'
        description: '''
        HTTP URL endpoint, must be a valid URL.
        '''
    required: ['url']

Handler

handler = ({config}) ->
  throw Error "Required Option: `password` is required if principal is provided" if config.principal and not config.password
  throw Error "Required Option: `data` is required with POST and PUT requests" if config.method in ['POST', 'PUT'] and not config.data
  if config.data? and typeof config.data isnt 'string'
    config.http_headers['Accept'] ?= 'application/json'
    config.http_headers['Content-Type'] ?= 'application/json'
    config.data = JSON.stringify config.data
  url_info = url.parse config.url
  config.http_headers ?= []
  config.cookies ?= []
  err = null
  output =
    body: []
    data: undefined
    http_version: undefined
    headers: {}
    status_code: undefined
    status_message: undefined
    type: undefined
  try
    {code, stdout} = await @execute
      command: """
      #{ unless config.principal then '' else [
        'echo', config.password, '|', 'kinit', config.principal, '>/dev/null'
      ].join ' '}
      command -v curl >/dev/null || exit 90
      #{[
        'curl'
        "--max-time '#{Math.max(config.timeout/1000)}'" if config.timeout
        '--include' # Include protocol headers in the output (H/F)
        '--silent' # Dont print progression to stderr
        '--fail' if config.fail
        '--insecure' if not config.cacert and url_info.protocol is 'https:'
        '--cacert #{config.cacert}' if config.cacert
        '--negotiate -u:' if config.negotiate
        '--location' if config.location
        ...("--header '#{header.replace '\'', '\\\''}:#{value.replace '\'', '\\\''}'" for header, value of config.http_headers)
        ...("--cookie '#{cookie.replace '\'', '\\\''}'" for cookie in config.cookies)
        "-o #{config.target}" if config.target
        "-x #{config.proxy}" if config.proxy
        "-X #{config.method}" if config.method isnt 'GET'
        "--data #{utils.string.escapeshellarg config.data}" if config.data
        "#{config.url}"
      ].join ' '}
      """
      trap: true
    output.raw = stdout
    done_with_header = false
    for line, i in utils.string.lines stdout
      if output.body.length is 0 and /^HTTP\/[\d.]+ \d+/.test line
        done_with_header = false
        output.headers = {}
        [http_version, status_code, status_message...] = line.split ' '
        output.http_version = http_version.substr 5
        output.status_code = parseInt status_code, 10
        output.status_message = status_message.join ' '
        just_finished_header = false
        continue
      else if line is ''
        done_with_header = true
        continue
      unless done_with_header
        [name, value...] = line.split ':'
        output.headers[name.trim()] = value.join(':').trim()
      else
        output.body.push line
  catch err
    if code = utils.curl.error(err.exit_code)
      throw utils.error code, [
        "the curl command exited with code `#{err.exit_code}`."
      ]
    else if err.exit_code is 90
      throw utils.error 'NIKITA_NETWORK_DOWNLOAD_CURL_REQUIRED', [
        'the `curl` command could not be found'
        'and is required to perform HTTP requests,'
        'make sure it is available in your `$PATH`.'
      ]
    else throw err
  await @fs.chmod
    $if: config.target and config.mode
    mode: config.mode
  await @fs.chown
    $if: config.target and config.uid? or config.gid?
    target: config.target
    uid: config.uid
    gid: config.gid
  output.type = 'json' if /^application\/json(;|$)/.test output.headers['Content-Type']
  output.body = output.body.join ''
  switch output.type
    when 'json' then output.data = JSON.parse output.body
  output

Exports

module.exports =
  handler: handler
  metadata:
    definitions: definitions

Dependencies

url = require 'url'
utils = require '../utils'
Edit on GitHub
Navigate
About

Nikita is an open source project hosted on GitHub and developed by Adaltas.