Skip to content
This repository was archived by the owner on Jul 30, 2024. It is now read-only.

Overhaul http and https module #80

Merged
merged 1 commit into from
Sep 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ The following core Node.js modules (v8.7.0+) have been implemented:
| [dns](https://nodejs.org/api/dns.html) | :heavy_check_mark: |
| [events](https://nodejs.org/api/events.html) | :heavy_check_mark: |
| [fs](https://nodejs.org/api/fs.html) | :heavy_check_mark: |
| [http](https://nodejs.org/api/http.html) | |
| [http](https://nodejs.org/api/http.html) | :heavy_check_mark: |
| [http2](https://nodejs.org/api/http2.html) | |
| [https](https://nodejs.org/api/https.html) | |
| [https](https://nodejs.org/api/https.html) | :heavy_check_mark: |
| [net](https://nodejs.org/api/net.html) | |
| [os](https://nodejs.org/api/os.html) | :heavy_check_mark: |
| [path](https://nodejs.org/api/path.html) | :heavy_check_mark: |
Expand Down
13 changes: 10 additions & 3 deletions app/current/src/main/scala/io/scalajs/nodejs/http/Agent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.scalajs.util.PromiseHelper._

import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport

/**
* The HTTP Agent is used for pooling sockets used in HTTP client requests.
Expand All @@ -14,7 +15,8 @@ import scala.scalajs.js
* require developers to manually close the HTTP clients using KeepAlive.
*/
@js.native
trait Agent extends js.Object {
@JSImport("http", "Agent")
class Agent(options: AgentOptions = js.native) extends js.Object {

/////////////////////////////////////////////////////////////////////////////////
// Properties
Expand Down Expand Up @@ -56,7 +58,7 @@ trait Agent extends js.Object {
* @example agent.sockets
*/
// TODO what is the underlying object?
def sockets: js.Array[js.Any] = js.native
def sockets: js.Object = js.native

/////////////////////////////////////////////////////////////////////////////////
// Methods
Expand All @@ -75,6 +77,10 @@ trait Agent extends js.Object {
*/
def createConnection(options: ConnectionOptions, callback: js.Function): Unit = js.native

def keepSocketAlive(socket: net.Socket): Unit = js.native

def reuseSocket(socket: net.Socket, request: ClientRequest): Unit = js.native

/**
* Destroy any sockets that are currently in use by the agent.
*
Expand All @@ -85,6 +91,7 @@ trait Agent extends js.Object {
*/
def destroy(): Unit = js.native

def getName(options: GetNameOptions): String = js.native
}

/**
Expand All @@ -95,7 +102,7 @@ object Agent {
/**
* Agent Extensions
*/
implicit class AgentExtensions(val agent: Agent) extends AnyVal {
implicit final class AgentExtensions(val agent: Agent) extends AnyVal {

/**
* Produces a socket/stream to be used for HTTP requests. By default, this function is the same
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.scalajs.nodejs.http

import scala.scalajs.js

class AgentOptions(
var keepAlive: js.UndefOr[Boolean] = js.undefined,
var keepAliveMsecs: js.UndefOr[Int] = js.undefined,
var maxSockets: js.UndefOr[Double] = js.undefined,
var maxFreeSockets: js.UndefOr[Int] = js.undefined,
var timeout: js.UndefOr[Int] = js.undefined
) extends js.Object
155 changes: 42 additions & 113 deletions app/current/src/main/scala/io/scalajs/nodejs/http/ClientRequest.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package io.scalajs.nodejs
package http

import com.thoughtworks.enableIf
import io.scalajs.nodejs.buffer.Buffer
import io.scalajs.nodejs.net.Socket
import io.scalajs.nodejs.stream.Readable
import io.scalajs.util.PromiseHelper._

import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport
import scala.scalajs.js.typedarray.Uint8Array
import scala.scalajs.js.{Any, |}

/**
* http.ClientRequest - This object is created internally and returned from http.request(). It represents an in-progress
Expand All @@ -31,11 +33,25 @@ import scala.scalajs.js.annotation.JSImport
*/
@js.native
@JSImport("http", "ClientRequest")
class ClientRequest extends Readable {
class ClientRequest extends stream.Writable {

def headers: js.Dictionary[String] = js.native
def aborted: Int | Boolean = js.native

def socket: Socket = js.native
def connection: net.Socket = js.native

def finished: Boolean = js.native

var maxHeadersCount: Int | Null = js.native

def path: String = js.native

def socket: net.Socket = js.native

@enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12)
def writableEnded: Boolean = js.native

@enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12)
def writableFinished: Boolean = js.native

/////////////////////////////////////////////////////////////////////////////////
// Methods
Expand All @@ -48,34 +64,6 @@ class ClientRequest extends Readable {
*/
def abort(): Unit = js.native

/**
* Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream.
* If the request is chunked, this will send the terminating '0\r\n\r\n'.
* @see [[https://nodejs.org/api/http.html#http_request_end_data_encoding_callback]]
*/
def end(data: js.Any, encoding: String, callback: js.Function): Unit = js.native

/**
* Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream.
* If the request is chunked, this will send the terminating '0\r\n\r\n'.
* @see [[https://nodejs.org/api/http.html#http_request_end_data_encoding_callback]]
*/
def end(data: js.Any, encoding: String): Unit = js.native

/**
* Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream.
* If the request is chunked, this will send the terminating '0\r\n\r\n'.
* @see [[https://nodejs.org/api/http.html#http_request_end_data_encoding_callback]]
*/
def end(data: js.Any): Unit = js.native

/**
* Finishes sending the request. If any parts of the body are unsent, it will flush them to the stream.
* If the request is chunked, this will send the terminating '0\r\n\r\n'.
* @see [[https://nodejs.org/api/http.html#http_request_end_data_encoding_callback]]
*/
def end(): Unit = js.native

/**
* Flush the request headers.
*
Expand All @@ -90,39 +78,27 @@ class ClientRequest extends Readable {
*/
def flushHeaders(): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setNoDelay() will be called.
*/
def setNoDelay(noDelay: Int): Unit = js.native
def getHeader[T <: js.Any](name: String): T = js.native

/**
* Once a socket is assigned to this request and is connected socket.setNoDelay() will be called.
*/
def setNoDelay(): Unit = js.native
def removeHeader(name: String): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setKeepAlive() will be called.
* @see [[https://nodejs.org/api/http.html#http_request_setsocketkeepalive_enable_initialdelay]]
*/
def setSocketKeepAlive(enable: Boolean, initialDelay: Int): Unit = js.native
def setHeader(name: String, value: js.Any): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setKeepAlive() will be called.
* @see [[https://nodejs.org/api/http.html#http_request_setsocketkeepalive_enable_initialdelay]]
* Once a socket is assigned to this request and is connected socket.setNoDelay() will be called.
*/
def setSocketKeepAlive(enable: Boolean): Unit = js.native
def setNoDelay(noDelay: Int): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setKeepAlive() will be called.
* @see [[https://nodejs.org/api/http.html#http_request_setsocketkeepalive_enable_initialdelay]]
* Once a socket is assigned to this request and is connected socket.setNoDelay() will be called.
*/
def setSocketKeepAlive(initialDelay: Int): Unit = js.native
def setNoDelay(noDelay: Boolean = js.native): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setKeepAlive() will be called.
* @see [[https://nodejs.org/api/http.html#http_request_setsocketkeepalive_enable_initialdelay]]
*/
def setSocketKeepAlive(): Unit = js.native
def setSocketKeepAlive(enable: Boolean = js.native, initialDelay: Int = js.native): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setTimeout() will be called.
Expand All @@ -132,53 +108,7 @@ class ClientRequest extends Readable {
* Same as binding to the timeout event.</li>
* </ul>
*/
def setTimeout(timeout: Int, callback: js.Function): Unit = js.native

/**
* Once a socket is assigned to this request and is connected socket.setTimeout() will be called.
* <ul>
* <li>timeout {Number} Milliseconds before a request is considered to be timed out.</li>
* <li>callback {Function} Optional function to be called when a timeout occurs.
* Same as binding to the timeout event.</li>
* </ul>
*/
def setTimeout(timeout: Int): Unit = js.native

/**
* Sends a chunk of the body. By calling this method many times, the user can stream a
* request body to a server--in that case it is suggested to use the ['Transfer-Encoding', 'chunked']
* header line when creating the request.
*
* The chunk argument should be a Buffer or a string.
* The encoding argument is optional and only applies when chunk is a string. Defaults to 'utf8'.
* The callback argument is optional and will be called when this chunk of data is flushed.
* Returns request.
*/
def write(chunk: js.Any, encoding: String, callback: js.Function): Unit = js.native

/**
* Sends a chunk of the body. By calling this method many times, the user can stream a
* request body to a server--in that case it is suggested to use the ['Transfer-Encoding', 'chunked']
* header line when creating the request.
*
* The chunk argument should be a Buffer or a string.
* The encoding argument is optional and only applies when chunk is a string. Defaults to 'utf8'.
* The callback argument is optional and will be called when this chunk of data is flushed.
* Returns request.
*/
def write(chunk: js.Any, encoding: String): Unit = js.native

/**
* Sends a chunk of the body. By calling this method many times, the user can stream a
* request body to a server--in that case it is suggested to use the ['Transfer-Encoding', 'chunked']
* header line when creating the request.
*
* The chunk argument should be a Buffer or a string.
* The encoding argument is optional and only applies when chunk is a string. Defaults to 'utf8'.
* The callback argument is optional and will be called when this chunk of data is flushed.
* Returns request.
*/
def write(chunk: js.Any): Unit = js.native
def setTimeout(timeout: Int, callback: js.Function = js.native): Unit = js.native

}

Expand All @@ -187,10 +117,7 @@ class ClientRequest extends Readable {
*/
object ClientRequest {

/**
* Client Request Events
*/
implicit class ClientRequestEvents(val client: ClientRequest) extends AnyVal {
implicit final class ClientRequestExtensions(val client: ClientRequest) extends AnyVal {

/**
* Emitted when the request has been aborted by the client. This event is only emitted on the first call to abort().
Expand Down Expand Up @@ -246,23 +173,25 @@ object ClientRequest {
@inline
def onUpgrade(callback: (IncomingMessage, Socket, Buffer) => Any): client.type = client.on("upgrade", callback)

}

/**
* Client Request Extensions
*/
implicit class ClientRequestEnrichment(val client: ClientRequest) extends AnyVal {
@inline
def endFuture(data: Uint8Array): Future[Unit] = {
promiseWithError0[Error](client.end(data, _))
}

@inline
def endFuture(data: js.Any, encoding: String): Future[js.Any] = {
promiseWithError1[SystemError, js.Any](client.end(data, encoding, _))
def endFuture(data: String, encoding: String): Future[Unit] = {
promiseWithError0[Error](client.end(data, encoding, _))
}

@inline
def writeFuture(chunk: js.Any, encoding: String): Future[js.Any] = {
promiseWithError1[SystemError, js.Any](client.write(chunk, encoding, _))
def writeFuture(chunk: Uint8Array): Future[Unit] = {
promiseWithError0[Error](client.write(chunk, _))
}

@inline
def writeFuture(chunk: String, encoding: String): Future[Unit] = {
promiseWithError0[Error](client.write(chunk, encoding, _))
}
}

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
package io.scalajs.nodejs.http

import scala.scalajs.js
import scala.scalajs.js.typedarray.Uint8Array
import scala.scalajs.js.|

/**
* Connection Options
* @param keepAlive Keep sockets around in a pool to be used by other requests in the future. Default = false
* @param keepAliveMsecs When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive.
* Default = 1000. Only relevant if keepAlive is set to true.
* @param maxSockets Maximum number of sockets to allow per host. Default = Infinity.
* @param maxFreeSockets Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to
* true (default: 256).
*/
class ConnectionOptions(var keepAlive: js.UndefOr[Boolean] = js.undefined,
var keepAliveMsecs: js.UndefOr[Int] = js.undefined,
var maxSockets: js.UndefOr[Double] = js.undefined,
var maxFreeSockets: js.UndefOr[Int] = js.undefined)
extends js.Object
class ConnectionOptions(
// for socket.connect(option)
var port: Int,
var host: js.UndefOr[String] = js.undefined,
var localAddress: js.UndefOr[String] = js.undefined,
var localPort: js.UndefOr[Int] = js.undefined,
var family: js.UndefOr[Int] = js.undefined,
var hints: js.UndefOr[Int] = js.undefined,
var lookup: js.UndefOr[js.Function1[String, Any]] = js.undefined,
var onread: js.UndefOr[OnreadObject] = js.undefined,
// for new Socket(option)
var fd: js.UndefOr[Int] = js.undefined,
var allowHalfOpen: js.UndefOr[Boolean] = js.undefined,
var readable: js.UndefOr[Boolean] = js.undefined,
var writable: js.UndefOr[Int] = js.undefined
) extends js.Object

class OnreadObject(
var buffer: Uint8Array | js.Function0[Uint8Array],
var calback: js.Function2[Int, Uint8Array, Boolean]
) extends js.Object
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.scalajs.nodejs.http

import scala.scalajs.js

class GetNameOptions(
var host: String,
var port: js.UndefOr[Int] = js.undefined,
var localAddress: js.UndefOr[String] = js.undefined,
var family: js.UndefOr[Int] = js.undefined
) extends js.Object
Loading