docs: function EventSource (url, eventSourceInitDict) {
    var readyState = EventSource.CONNECTING
    Object.defineProperty(this, 'readyState', {
      get: function () {
        return readyState
      }
    })
  
    Object.defineProperty(this, 'url', {
      get: function () {
        return url
      }
    })
  
    var self = this
    self.reconnectInterval = 1000
  
    function onConnectionClosed (message) {
      if (readyState === EventSource.CLOSED) return
      readyState = EventSource.CONNECTING
      _emit('error', new Event('error', {message: message}))
  
      // The url may have been changed by a temporary
      // redirect. If that's the case, revert it now.
      if (reconnectUrl) {
        url = reconnectUrl
        reconnectUrl = null
      }
      setTimeout(function () {
        if (readyState !== EventSource.CONNECTING) {
          return
        }
        connect()
      }, self.reconnectInterval)
    }
  
    var req
    var lastEventId = ''
    if (eventSourceInitDict && eventSourceInitDict.headers && eventSourceInitDict.headers['Last-Event-ID']) {
      lastEventId = eventSourceInitDict.headers['Last-Event-ID']
      delete eventSourceInitDict.headers['Last-Event-ID']
    }
  
    var discardTrailingNewline = false
    var data = ''
    var eventName = ''
  
    var reconnectUrl = null
  
    function connect () {
      var options = parse(url)
      var isSecure = options.protocol === 'https:'
      options.headers = { 'Cache-Control': 'no-cache', 'Accept': 'text/event-stream' }
      if (lastEventId) options.headers['Last-Event-ID'] = lastEventId
      if (eventSourceInitDict && eventSourceInitDict.headers) {
        for (var i in eventSourceInitDict.headers) {
          var header = eventSourceInitDict.headers[i]
          if (header) {
            options.headers[i] = header
          }
        }
      }
  
      // Legacy: this should be specified as `eventSourceInitDict.https.rejectUnauthorized`,
      // but for now exists as a backwards-compatibility layer
      options.rejectUnauthorized = !(eventSourceInitDict && !eventSourceInitDict.rejectUnauthorized)
  
      // If specify http proxy, make the request to sent to the proxy server,
      // and include the original url in path and Host headers
      var useProxy = eventSourceInitDict && eventSourceInitDict.proxy
      if (useProxy) {
        var proxy = parse(eventSourceInitDict.proxy)
        isSecure = proxy.protocol === 'https:'
  
        options.protocol = isSecure ? 'https:' : 'http:'
        options.path = url
        options.headers.Host = options.host
        options.hostname = proxy.hostname
        options.host = proxy.host
        options.port = proxy.port
      }
  
      // If https options are specified, merge them into the request options
      if (eventSourceInitDict && eventSourceInitDict.https) {
        for (var optName in eventSourceInitDict.https) {
          if (httpsOptions.indexOf(optName) === -1) {
            continue
          }
  
          var option = eventSourceInitDict.https[optName]
          if (option !== undefined) {
            options[optName] = option
          }
        }
      }
  
      // Pass this on to the XHR
      if (eventSourceInitDict && eventSourceInitDict.withCredentials !== undefined) {
        options.withCredentials = eventSourceInitDict.withCredentials
      }
  
      req = (isSecure ? https : http).request(options, function (res) {
        // Handle HTTP errors
        if (res.statusCode === 500 || res.statusCode === 502 || res.statusCode === 503 || res.statusCode === 504) {
          _emit('error', new Event('error', {status: res.statusCode, message: res.statusMessage}))
          onConnectionClosed()
          return
        }
  
        // Handle HTTP redirects
        if (res.statusCode === 301 || res.statusCode === 307) {
          if (!res.headers.location) {
            // Server sent redirect response without Location header.
            _emit('error', new Event('error', {status: res.statusCode, message: res.statusMessage}))
            return
          }
          if (res.statusCode === 307) reconnectUrl = url
          url = res.headers.location
          process.nextTick(connect)
          return
        }
  
        if (res.statusCode !== 200) {
          _emit('error', new Event('error', {status: res.statusCode, message: res.statusMessage}))
          return self.close()
        }
  
        readyState = EventSource.OPEN
        res.on('close', function () {
          res.removeAllListeners('close')
          res.removeAllListeners('end')
          onConnectionClosed()
        })
  
        res.on('end', function () {
          res.removeAllListeners('close')
          res.removeAllListeners('end')
          onConnectionClosed()
        })
        _emit('open', new Event('open'))
  
        // text/event-stream parser adapted from webkit's
        // Source/WebCore/page/EventSource.cpp
        var isFirst = true
        var buf
        res.on('data', function (chunk) {
          buf = buf ? Buffer.concat([buf, chunk]) : chunk
          if (isFirst && hasBom(buf)) {
            buf = buf.slice(bom.length)
          }
  
          isFirst = false
          var pos = 0
          var length = buf.length
  
          while (pos < length) {
            if (discardTrailingNewline) {
              if (buf[pos] === lineFeed) {
                ++pos
              }
              discardTrailingNewline = false
            }
  
            var lineLength = -1
            var fieldLength = -1
            var c
  
            for (var i = pos; lineLength < 0 && i < length; ++i) {
              c = buf[i]
              if (c === colon) {
                if (fieldLength < 0) {
                  fieldLength = i - pos
                }
              } else if (c === carriageReturn) {
                discardTrailingNewline = true
                lineLength = i - pos
              } else if (c === lineFeed) {
                lineLength = i - pos
              }
            }
  
            if (lineLength < 0) {
              break
            }
  
            parseEventStreamLine(buf, pos, fieldLength, lineLength)
  
            pos += lineLength + 1
          }
  
          if (pos === length) {
            buf = void 0
          } else if (pos > 0) {
            buf = buf.slice(pos)
          }
        })
      })
  
      req.on('error', function (err) {
        onConnectionClosed(err.message)
      })
  
      if (req.setNoDelay) req.setNoDelay(true)
      req.end()
    }
  
    connect()
  
    function _emit () {
      if (self.listeners(arguments[0]).length > 0) {
        self.emit.apply(self, arguments)
      }
    }
  
    this._close = function () {
      if (readyState === EventSource.CLOSED) return
      readyState = EventSource.CLOSED
      if (req.abort) req.abort()
      if (req.xhr && req.xhr.abort) req.xhr.abort()
    }
  
    function parseEventStreamLine (buf, pos, fieldLength, lineLength) {
      if (lineLength === 0) {
        if (data.length > 0) {
          var type = eventName || 'message'
          _emit(type, new MessageEvent(type, {
            data: data.slice(0, -1), // remove trailing newline
            lastEventId: lastEventId,
            origin: original(url)
          }))
          data = ''
        }
        eventName = void 0
      } else if (fieldLength > 0) {
        var noValue = fieldLength < 0
        var step = 0
        var field = buf.slice(pos, pos + (noValue ? lineLength : fieldLength)).toString()
  
        if (noValue) {
          step = lineLength
        } else if (buf[pos + fieldLength + 1] !== space) {
          step = fieldLength + 1
        } else {
          step = fieldLength + 2
        }
        pos += step
  
        var valueLength = lineLength - step
        var value = buf.slice(pos, pos + valueLength).toString()
  
        if (field === 'data') {
          data += value + '\n'
        } else if (field === 'event') {
          eventName = value
        } else if (field === 'id') {
          lastEventId = value
        } else if (field === 'retry') {
          var retry = parseInt(value, 10)
          if (!Number.isNaN(retry)) {
            self.reconnectInterval = retry
          }
        }
      }
    }
  }