diff --git a/README.md b/README.md index 09fc8514c..61632d258 100644 --- a/README.md +++ b/README.md @@ -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: | diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/Agent.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/Agent.scala index ac8df6098..ff19669bf 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/Agent.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/Agent.scala @@ -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. @@ -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 @@ -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 @@ -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. * @@ -85,6 +91,7 @@ trait Agent extends js.Object { */ def destroy(): Unit = js.native + def getName(options: GetNameOptions): String = js.native } /** @@ -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 diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/AgentOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/AgentOptions.scala new file mode 100644 index 000000000..d9e5f93cd --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/AgentOptions.scala @@ -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 diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/ClientRequest.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/ClientRequest.scala index cbf259288..6795b91ca 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/ClientRequest.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/ClientRequest.scala @@ -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 @@ -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 @@ -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. * @@ -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. @@ -132,53 +108,7 @@ class ClientRequest extends Readable { * Same as binding to the timeout event. * */ - 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. - * - */ - 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 } @@ -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(). @@ -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, _)) + } } } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/ConnectionOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/ConnectionOptions.scala index b81d53d73..d3229ad1a 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/ConnectionOptions.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/ConnectionOptions.scala @@ -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 diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/GetNameOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/GetNameOptions.scala new file mode 100644 index 000000000..df81ba10b --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/GetNameOptions.scala @@ -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 diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/Http.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/Http.scala index 6a51034b6..80c4dd2f0 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/Http.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/Http.scala @@ -1,9 +1,11 @@ package io.scalajs.nodejs.http -import io.scalajs.nodejs.events.IEventEmitter +import com.thoughtworks.enableIf +import io.scalajs.nodejs.url.URL import scala.scalajs.js import scala.scalajs.js.annotation.JSImport +import scala.scalajs.js.| /** * To use the HTTP server and client one must require('http'). @@ -14,7 +16,7 @@ import scala.scalajs.js.annotation.JSImport * @see https://nodejs.org/api/http.html */ @js.native -trait Http extends IEventEmitter { +trait Http extends js.Object { ///////////////////////////////////////////////////////////////////////////////// // Properties @@ -35,94 +37,36 @@ trait Http extends IEventEmitter { * A collection of all the standard HTTP response status codes, and the short description of each. * @example http.STATUS_CODES[404] === 'Not Found'. */ - val STATUS_CODES: js.Dictionary[String] = js.native + val STATUS_CODES: StatusCodes = js.native ///////////////////////////////////////////////////////////////////////////////// // Methods ///////////////////////////////////////////////////////////////////////////////// - /** - * Constructs a new HTTP client. port and host refer to the server to be connected to. - * @example http.createClient([port][, host]) - */ - @deprecated("Use request() instead", "4.x") - def createClient(port: Int, host: String): Client = js.native - - /** - * Constructs a new HTTP client. port and host refer to the server to be connected to. - * @example http.createClient([port][, host]) - */ - @deprecated("Use request() instead", "4.x") - def createClient(port: Int): Client = js.native - - /** - * Constructs a new HTTP client. port and host refer to the server to be connected to. - * @example http.createClient([port][, host]) - */ - @deprecated("Use request() instead", "4.x") - def createClient(host: String): Client = js.native - - /** - * Constructs a new HTTP client. port and host refer to the server to be connected to. - * @example http.createClient([port][, host]) - */ - @deprecated("Use request() instead", "4.x") - def createClient(): Client = js.native - - /** - * Returns a new instance of http.Server. - * @example http.createServer([requestListener]) - */ - def createServer[A <: ClientRequest, B <: ServerResponse](callback: js.Function2[A, B, Any]): Server = js.native - - /** - * Returns a new instance of http.Server. - * @example http.createServer([requestListener]) - */ - def createServer(): Server = js.native - - /** - * Since most requests are GET requests without bodies, Node.js provides this convenience method. The only difference - * between this method and http.request() is that it sets the method to GET and calls req.end() automatically. - * @example http.get('https://encrypted.google.com/', (res) => { ... }) - */ - def get(url: String, callback: js.Function1[ServerResponse, Any]): Unit = js.native - - /** - * Since most requests are GET requests without bodies, Node.js provides this convenience method. The only difference - * between this method and http.request() is that it sets the method to GET and calls req.end() automatically. - * @example http.get(options, (res) => { ... }) - */ - def get(options: RequestOptions, callback: js.Function): Unit = js.native - - /** - * Node.js maintains several connections per server to make HTTP requests. - * This function allows one to transparently issue requests. - * @example http.request(options[, callback]) - */ - def request(options: RequestOptions, callback: js.Function): Unit = js.native - - /** - * Node.js maintains several connections per server to make HTTP requests. - * This function allows one to transparently issue requests. - * @example http.request(options[, callback]) - */ - def request(options: RequestOptions): Unit = js.native - - /** - * Node.js maintains several connections per server to make HTTP requests. - * This function allows one to transparently issue requests. - * @example http.request(options[, callback]) - */ - def request(url: String, callback: js.Function): Unit = js.native - - /** - * Node.js maintains several connections per server to make HTTP requests. - * This function allows one to transparently issue requests. - * @example http.request(options[, callback]) - */ - def request(url: String): Unit = js.native - + def createServer(options: ServerOptions, requestListener: js.Function2[ClientRequest, ServerResponse, Any]): Server = + js.native + def createServer(requestListener: js.Function2[ClientRequest, ServerResponse, Any] = js.native): Server = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def get(url: String | URL, + options: RequestOptions, + callback: js.Function1[ServerResponse, Any] = js.native): ClientRequest = js.native + def get(url: String | URL, callback: js.Function1[ServerResponse, Any]): ClientRequest = js.native + def get(url: String | URL): ClientRequest = js.native + def get(options: RequestOptions): ClientRequest = js.native + def get(options: RequestOptions, callback: js.Function): ClientRequest = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def maxHeaderSize: Int = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def request(url: String | URL, + options: RequestOptions, + callback: js.Function1[ServerResponse, Any] = js.native): Unit = js.native + def request(url: String | URL, callback: js.Function1[ServerResponse, Any]): Unit = js.native + def request(url: String | URL): Unit = js.native + def request(options: RequestOptions): Unit = js.native + def request(options: RequestOptions, callback: js.Function1[ServerResponse, Any]): Unit = js.native } /** diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/IncomingMessage.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/IncomingMessage.scala index 98d11c00d..e73c105c2 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/IncomingMessage.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/IncomingMessage.scala @@ -1,10 +1,12 @@ package io.scalajs.nodejs.http +import com.thoughtworks.enableIf import io.scalajs.nodejs.net.Socket import io.scalajs.nodejs.stream.Readable import scala.concurrent.duration.FiniteDuration import scala.scalajs.js +import scala.scalajs.js.annotation.JSImport /** * An IncomingMessage object is created by http.Server or http.ClientRequest and passed as the first argument @@ -13,7 +15,15 @@ import scala.scalajs.js * @see [[https://nodejs.org/api/http.html#http_class_http_incomingmessage]] */ @js.native -trait IncomingMessage extends Readable { +@JSImport("http", "IncomingMessage") +class IncomingMessage extends Readable { + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def aborted: Boolean = js.native + + def complete: Boolean = js.native + + def destroy(error: io.scalajs.nodejs.Error = js.native): Unit = js.native /** * The request/response headers object. Key-value pairs of header names and values. Header names are lower-cased. @@ -32,7 +42,7 @@ trait IncomingMessage extends Readable { * Only valid for request obtained from http.Server. The request method as a string. Read only. Example: 'GET', 'DELETE'. * @example message.method */ - def method: String = js.native + def method: js.UndefOr[String] = js.native /** * The raw request/response headers list exactly as they were received. Note that the keys and values are @@ -48,30 +58,20 @@ trait IncomingMessage extends Readable { */ def rawTrailers: js.Array[String] = js.native - /** - * Calls message.connection.setTimeout(msecs, callback). - * @example message.setTimeout(msecs, callback) - */ - def setTimeout(msecs: Int, callback: js.Function): Unit = js.native - - /** - * Calls message.connection.setTimeout(msecs, callback). - * @example message.setTimeout(msecs, callback) - */ - def setTimeout(msecs: Double, callback: js.Function): Unit = js.native + def setTimeout(msecs: Double, callback: js.Function): this.type = js.native /** * Only valid for response obtained from http.ClientRequest. The 3-digit HTTP response status code (e.g. 404). * @example message.statusCode */ - def statusCode: Int = js.native + def statusCode: js.UndefOr[Int] = js.native /** * Only valid for response obtained from http.ClientRequest. The HTTP response status message (reason phrase) * (e.g. OK or Internal Server Error). * @example message.statusMessage */ - def statusMessage: String = js.native + def statusMessage: js.UndefOr[String] = js.native /** * The net.Socket object associated with the connection. With HTTPS support, use request.socket.getPeerCertificate() @@ -84,14 +84,14 @@ trait IncomingMessage extends Readable { * The request/response trailers object. Only populated at the 'end' event. * @example message.trailers */ - def trailers: js.Array[String] = js.native + def trailers: js.Dictionary[js.Any] = js.native /** * Only valid for request obtained from http.Server. Request URL string. This contains only the URL that is * present in the actual HTTP request. * @example message.url */ - def url: String = js.native + def url: js.UndefOr[String] = js.native } @@ -103,7 +103,7 @@ object IncomingMessage { /** * Incoming Message Extensions */ - implicit class IncomingMessageExtensions(val message: IncomingMessage) extends AnyVal { + implicit final class IncomingMessageExtensions(val message: IncomingMessage) extends AnyVal { @inline def onClose(callback: js.Function): message.type = message.on("close", callback) diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/RequestOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/RequestOptions.scala index 7dd946dee..33c6b26da 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/RequestOptions.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/RequestOptions.scala @@ -1,40 +1,23 @@ package io.scalajs.nodejs.http import scala.scalajs.js +import scala.scalajs.js.| -/** - * Client Request Options - * @param protocol Protocol to use. Defaults to 'http:'. - * @param host Alias for host. To support url.parse() hostname is preferred over host. - * @param hostname Alias for host. To support url.parse() hostname is preferred over host. - * @param family IP address family to use when resolving host and hostname. Valid values are 4 or 6. When - * unspecified, both IP v4 and v6 will be used. - * @param port Port of remote server. Defaults to 80. - * @param localAddress Local interface to bind for network connections. - * @param socketPath Unix Domain Socket (use one of host:port or socketPath). - * @param method A string specifying the HTTP request method. Defaults to 'GET'. - * @param path Request path. Defaults to '/'. Should include query string if any. E.G. '/index.html?page=12'. - * An exception is thrown when the request path contains illegal characters. Currently, only spaces - * are rejected but that may change in the future. - * @param headers An object containing request headers. - * @param auth Basic authentication i.e. 'user:password' to compute an Authorization header. - * @param agent Controls Agent behavior. When an Agent is used request will default to Connection: keep-alive. - * Possible values: TODO - * @param createConnection A function that produces a socket/stream to use for the request when the agent option is not used. - * This can be used to avoid creating a custom Agent class just to override the default createConnection function. - * @see [[Agent.createConnection() ]] - */ -class RequestOptions(var protocol: js.UndefOr[String] = js.undefined, - var host: js.UndefOr[String] = js.undefined, - var hostname: js.UndefOr[String] = js.undefined, - var family: js.UndefOr[String] = js.undefined, - var port: js.UndefOr[Int] = js.undefined, - var localAddress: js.UndefOr[String] = js.undefined, - var socketPath: js.UndefOr[String] = js.undefined, - var method: js.UndefOr[String] = js.undefined, - var path: js.UndefOr[String] = js.undefined, - var headers: js.UndefOr[js.Object] = js.undefined, - var auth: js.UndefOr[String] = js.undefined, - var agent: js.UndefOr[String] = js.undefined, - var createConnection: js.UndefOr[js.Function] = js.undefined) - extends js.Object +class RequestOptions( + var agent: js.UndefOr[Agent | Boolean] = js.undefined, + var auth: js.UndefOr[String] = js.undefined, + var createConnection: js.UndefOr[js.Function] = js.undefined, + var defaultPort: js.UndefOr[Int] = js.undefined, + var family: js.UndefOr[Int] = js.undefined, + var headers: js.UndefOr[js.Dictionary[js.Any]] = js.undefined, + var host: js.UndefOr[String] = js.undefined, + var hostname: js.UndefOr[String] = js.undefined, + var localAddress: js.UndefOr[String] = js.undefined, + var method: js.UndefOr[String] = js.undefined, + var path: js.UndefOr[String] = js.undefined, + var port: js.UndefOr[Int] = js.undefined, + var protocol: js.UndefOr[String] = js.undefined, + var setHost: js.UndefOr[Boolean] = js.undefined, + var socketPath: js.UndefOr[String] = js.undefined, + var timeout: js.UndefOr[Int] = js.undefined +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/Server.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/Server.scala index a70e5eea6..88eef1048 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/Server.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/Server.scala @@ -7,13 +7,21 @@ import io.scalajs.nodejs.net.Socket import scala.scalajs.js import scala.scalajs.js.annotation.JSImport +import scala.scalajs.js.| /** * http.Server - This class inherits from net.Server and has the following additional events */ @js.native @JSImport("http", "Server") -class Server extends net.Server +class Server extends net.Server { + var headersTimeout: Int = js.native + var maxHeadersCount: Int | Null = js.native + var timeout: Int = js.native + var keepAliveTimeout: Int = js.native + + def setTimeout(callback: js.Function): this.type = js.native +} /** * Server Companion diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/ServerOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/ServerOptions.scala new file mode 100644 index 000000000..f45254062 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/ServerOptions.scala @@ -0,0 +1,8 @@ +package io.scalajs.nodejs.http + +import scala.scalajs.js + +class ServerOptions( + var IncomingMessage: js.UndefOr[js.Function] = js.undefined, + var ServerResponse: js.UndefOr[js.Function] = js.undefined +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/ServerResponse.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/ServerResponse.scala index a3db79120..82bdc6ece 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/ServerResponse.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/ServerResponse.scala @@ -1,18 +1,18 @@ package io.scalajs.nodejs package http +import com.thoughtworks.enableIf import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.events.IEventEmitter -import io.scalajs.nodejs.stream.IDuplex import scala.scalajs.js +import scala.scalajs.js.| /** * Node.js http.ServerResponse * @see [[https://nodejs.org/api/http.html#http_class_http_serverresponse]] */ @js.native -trait ServerResponse extends IEventEmitter with IDuplex { +trait ServerResponse extends stream.Writable { ///////////////////////////////////////////////////////////////////////////////// // Properties @@ -54,6 +54,14 @@ trait ServerResponse extends IEventEmitter with IDuplex { */ var statusMessage: js.UndefOr[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 ///////////////////////////////////////////////////////////////////////////////// @@ -67,12 +75,20 @@ trait ServerResponse extends IEventEmitter with IDuplex { */ def addTrailers(headers: js.Any): Unit = js.native + def flushHeaders(): Unit = js.native + /** * Reads out a header that's already been queued but not sent to the client. * Note that the name is case insensitive. This can only be called before * headers get implicitly flushed. */ - def getHeader(name: String): js.UndefOr[String] = js.native + def getHeader[T <: js.Any](name: String): js.UndefOr[T] = js.native + + def getHeaderNames(): js.Array[String] = js.native + + def getHeaders(): js.Dictionary[js.Any] = js.native + + def hasHeader(name: String): Boolean = js.native /** * Removes a header that's queued for implicit sending. @@ -93,7 +109,7 @@ trait ServerResponse extends IEventEmitter with IDuplex { * Sets a single header value for implicit headers. If this header already exists in the to-be-sent headers, * its value will be replaced. Use an array of strings here if you need to send multiple headers with the same name. */ - def setHeader(name: String, value: String): Unit = js.native + def setHeader(name: String, value: js.Any): Unit = js.native /** * Sets the Socket's timeout value to msecs. If a callback is provided, then @@ -106,7 +122,7 @@ trait ServerResponse extends IEventEmitter with IDuplex { * * Returns response. */ - def setTimeout(msecs: Int, callback: js.Function): Unit = js.native + def setTimeout(msecs: Int, callback: js.Function = js.native): Unit = js.native def status(statusCode: Int): this.type = js.native @@ -118,18 +134,14 @@ trait ServerResponse extends IEventEmitter with IDuplex { */ def writeContinue(): Unit = js.native - /** - * Sends a response header to the request. The status code is a 3-digit HTTP status code, like 404. - * The last argument, headers, are the response headers. Optionally one can give a human-readable - * statusMessage as the second argument. - * @example response.writeHead(statusCode[, statusMessage][, headers]) - */ - def writeHead(statusCode: Int, statusMessage: String, headers: js.Any): Unit = js.native - - def writeHead(statusCode: Int, statusMessage: String): Unit = js.native - - def writeHead(statusCode: Int, headers: js.Any = null): Unit = js.native + // Todo: Return this.type when Node.js v10 dropped + def writeHead(statusCode: Int, statusMessage: String, headers: js.Object | js.Dictionary[_] = js.native): Unit = + js.native + def writeHead(statusCode: Int, headers: js.Object | js.Dictionary[_]): Unit = js.native + def writeHead(statusCode: Int): Unit = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def writeProcessing(): Unit = js.native } /** @@ -140,7 +152,7 @@ object ServerResponse { /** * Server Response Events */ - implicit class ServerResponseEvents(val response: ServerResponse) extends AnyVal { + implicit final class ServerResponseExtensions(val response: ServerResponse) extends AnyVal { @inline def onData(handler: Buffer => Any): response.type = response.on("data", handler) @@ -148,13 +160,6 @@ object ServerResponse { @inline def onFinish(handler: js.Function): response.type = response.on("finish", handler) - } - - /** - * Server Response Extensions - */ - implicit class ServerResponseExtensions(val response: ServerResponse) extends AnyVal { - /** * Sets the content-type for the response * @param contentType the given MIME type diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/StatusCodes.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/StatusCodes.scala new file mode 100644 index 000000000..1c015853e --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/StatusCodes.scala @@ -0,0 +1,71 @@ +package io.scalajs.nodejs.http + +import scala.scalajs.js + +@js.native +trait StatusCodes extends js.Object { + val `100`: String = js.native + val `101`: String = js.native + val `102`: String = js.native + val `103`: String = js.native + val `200`: String = js.native + val `201`: String = js.native + val `202`: String = js.native + val `203`: String = js.native + val `204`: String = js.native + val `205`: String = js.native + val `206`: String = js.native + val `207`: String = js.native + val `208`: String = js.native + val `226`: String = js.native + val `300`: String = js.native + val `301`: String = js.native + val `302`: String = js.native + val `303`: String = js.native + val `304`: String = js.native + val `305`: String = js.native + val `307`: String = js.native + val `308`: String = js.native + val `400`: String = js.native + val `401`: String = js.native + val `402`: String = js.native + val `403`: String = js.native + val `404`: String = js.native + val `405`: String = js.native + val `406`: String = js.native + val `407`: String = js.native + val `408`: String = js.native + val `409`: String = js.native + val `410`: String = js.native + val `411`: String = js.native + val `412`: String = js.native + val `413`: String = js.native + val `414`: String = js.native + val `415`: String = js.native + val `416`: String = js.native + val `417`: String = js.native + val `418`: String = js.native + val `421`: String = js.native + val `422`: String = js.native + val `423`: String = js.native + val `424`: String = js.native + val `425`: String = js.native + val `426`: String = js.native + val `428`: String = js.native + val `429`: String = js.native + val `431`: String = js.native + val `451`: String = js.native + val `500`: String = js.native + val `501`: String = js.native + val `502`: String = js.native + val `503`: String = js.native + val `504`: String = js.native + val `505`: String = js.native + val `506`: String = js.native + val `507`: String = js.native + val `508`: String = js.native + val `509`: String = js.native + val `510`: String = js.native + val `511`: String = js.native + +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/http/package.scala b/app/current/src/main/scala/io/scalajs/nodejs/http/package.scala index 2ba1d46b4..282f684df 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/http/package.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/http/package.scala @@ -48,7 +48,7 @@ package object http { */ @inline def requestFuture(options: RequestOptions): Future[ServerResponse] = { - promiseWithError1[SystemError, ServerResponse](http.request(options, _)) + promiseCallback1[ServerResponse](http.request(options, _)) } /** @@ -56,7 +56,7 @@ package object http { */ @inline def requestFuture(url: String): Future[ServerResponse] = { - promiseWithError1[SystemError, ServerResponse](http.request(url, _)) + promiseCallback1[ServerResponse](http.request(url, _)) } } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/https/Agent.scala b/app/current/src/main/scala/io/scalajs/nodejs/https/Agent.scala index 9bb90d022..92c8fef95 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/https/Agent.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/https/Agent.scala @@ -3,9 +3,11 @@ package io.scalajs.nodejs.https import io.scalajs.nodejs import scala.scalajs.js +import scala.scalajs.js.annotation.JSImport /** * HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module. */ @js.native -trait Agent extends nodejs.http.Agent +@JSImport("https", "Agent") +class Agent(options: AgentOptions = js.native) extends nodejs.http.Agent diff --git a/app/current/src/main/scala/io/scalajs/nodejs/https/AgentOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/https/AgentOptions.scala new file mode 100644 index 000000000..acb827da6 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/https/AgentOptions.scala @@ -0,0 +1,13 @@ +package io.scalajs.nodejs.https + +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, + var maxCachedSessions: js.UndefOr[Int], + var Int: js.UndefOr[String] +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/https/Https.scala b/app/current/src/main/scala/io/scalajs/nodejs/https/Https.scala index a8eb0d8cb..326925b5a 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/https/Https.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/https/Https.scala @@ -1,17 +1,19 @@ package io.scalajs.nodejs.https -import io.scalajs.nodejs.events.IEventEmitter -import io.scalajs.nodejs.http.RequestOptions +import com.thoughtworks.enableIf +import io.scalajs.nodejs.http.{ClientRequest, RequestOptions, ServerResponse} +import io.scalajs.nodejs.url.URL import scala.scalajs.js import scala.scalajs.js.annotation.JSImport +import scala.scalajs.js.| /** * HTTPS is the HTTP protocol over TLS/SSL. In Node.js this is implemented as a separate module. * @see https://nodejs.org/api/https.html */ @js.native -trait Https extends IEventEmitter { +trait Https extends js.Object { ///////////////////////////////////////////////////////////////////////////////// // Properties @@ -32,41 +34,24 @@ trait Https extends IEventEmitter { * @example https.createServer(options[, requestListener]) */ def createServer(options: ServerOptions, requestListener: js.Function): Server = js.native - - /** - * Returns a new HTTPS web server object. The options is similar to tls.createServer(). - * The requestListener is a function which is automatically added to the 'request' event. - * @example https.createServer(options[, requestListener]) - */ - def createServer(options: ServerOptions): Server = js.native - - /** - * Like http.get() but for HTTPS. - * @example https.get('https://encrypted.google.com/', (res) => { ... }) - * @see [[io.scalajs.nodejs.http.Http.get()]] - */ - def get(url: String, callback: js.Function): Unit = js.native - - /** - * Like http.get() but for HTTPS. - * @example https.get(options, (res) => { ... }) - * @see [[io.scalajs.nodejs.http.Http.get()]] - */ - def get(options: RequestOptions, callback: js.Function): Unit = js.native - - /** - * Makes a request to a secure web server. - * @param options can be an object or a string. If options is a string, it is automatically parsed with url.parse(). - * @example http.request(options, callback) - */ - def request(options: RequestOptions, callback: js.Function): Unit = js.native - - /** - * Makes a request to a secure web server. - * @param url can be an object or a string. If options is a string, it is automatically parsed with url.parse(). - * @example http.request(options, callback) - */ - def request(url: String, callback: js.Function): Unit = js.native + def createServer(requestListener: js.Function): Server = js.native + def createServer(options: ServerOptions): Server = js.native + def createServer(): Server = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def get(url: String | URL, options: RequestOptions, callback: js.Function1[ServerResponse, Any]): ClientRequest = + js.native + def get(url: String | URL, callback: js.Function1[ServerResponse, Any]): ClientRequest = js.native + def get(options: RequestOptions, callback: js.Function): ClientRequest = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def request(url: String | URL, + options: RequestOptions, + callback: js.Function1[ServerResponse, Any] = js.native): Unit = js.native + def request(url: String | URL, callback: js.Function1[ServerResponse, Any]): Unit = js.native + def request(url: String | URL): Unit = js.native + def request(options: RequestOptions): Unit = js.native + def request(options: RequestOptions, callback: js.Function1[ServerResponse, Any]): Unit = js.native } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/https/Server.scala b/app/current/src/main/scala/io/scalajs/nodejs/https/Server.scala index 12f8a46a1..a34cabf1e 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/https/Server.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/https/Server.scala @@ -1,6 +1,8 @@ package io.scalajs.nodejs package https +import com.thoughtworks.enableIf + import scala.scalajs.js import scala.scalajs.js.annotation.JSImport @@ -9,4 +11,12 @@ import scala.scalajs.js.annotation.JSImport */ @js.native @JSImport("https", "Server") -class Server extends tls.Server +class Server extends tls.Server { + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def headersTimeout: Int = js.native + + def maxHeaderCount: Int = js.native + def timeout: Int = js.native + def keepAliveTimeout: Int = js.native +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/https/ServerOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/https/ServerOptions.scala index ec19225fe..f228424de 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/https/ServerOptions.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/https/ServerOptions.scala @@ -1,39 +1,44 @@ package io.scalajs.nodejs.https +import io.scalajs.nodejs.buffer.Buffer +import io.scalajs.nodejs.tls.{SecureContext, SecureData, SecureDataObjectForm} + import scala.scalajs.js +import scala.scalajs.js.typedarray.{DataView, TypedArray} +import scala.scalajs.js.| -/** - * Server Options - * @param host A domain name or IP address of the server to issue the request to. Defaults to 'localhost'. - * @param hostname Alias for host. To support url.parse() hostname is preferred over host. - * @param family IP address family to use when resolving host and hostname. Valid values are 4 or 6. When - * unspecified, both IP v4 and v6 will be used. - * @param port Port of remote server. Defaults to 443. - * @param localAddress Local interface to bind for network connections. - * @param socketPath Unix Domain Socket (use one of host:port or socketPath). - * @param method A string specifying the HTTP request method. Defaults to 'GET'. - * @param path Request path. Defaults to '/'. Should include query string if any. E.G. '/index.html?page=12'. - * An exception is thrown when the request path contains illegal characters. Currently, only spaces - * are rejected but that may change in the future. - * @param headers An object containing request headers. - * @param auth Basic authentication i.e. 'user:password' to compute an Authorization header. - * @param agent Controls Agent behavior. When an Agent is used request will default to Connection: keep-alive. - * Possible values: - * - */ -class ServerOptions(var host: js.UndefOr[String] = js.undefined, - var hostname: js.UndefOr[String] = js.undefined, - var family: js.UndefOr[String] = js.undefined, - var port: js.UndefOr[Int] = js.undefined, - var localAddress: js.UndefOr[String] = js.undefined, - var socketPath: js.UndefOr[String] = js.undefined, - var method: js.UndefOr[String] = js.undefined, - var path: js.UndefOr[String] = js.undefined, - var headers: js.UndefOr[js.Dictionary[String]] = js.undefined, - var auth: js.UndefOr[js.Dictionary[String]] = js.undefined, - var agent: js.UndefOr[String] = js.undefined) - extends js.Object +class ServerOptions( + var ALPNProtocols: js.UndefOr[ + js.Array[String] | js.Array[TypedArray[_, _]] | js.Array[DataView] | TypedArray[_, _] | DataView + ] = js.undefined, + var enableTrace: js.UndefOr[Boolean] = js.undefined, + var handshakeTimeout: js.UndefOr[Int] = js.undefined, + var rejectUnauthorized: js.UndefOr[Boolean] = js.undefined, + var requestCert: js.UndefOr[Boolean] = js.undefined, + var sessionTimeout: js.UndefOr[Int] = js.undefined, + var SNICallback: js.UndefOr[js.Function2[String, js.Function2[io.scalajs.nodejs.Error, SecureContext, Any], Any]], + var ticketKeys: js.UndefOr[Buffer] = js.undefined, + // Options for net.createServers + val allowHalfOpen: js.UndefOr[Boolean] = js.undefined, + val pauseOnConnect: js.UndefOr[Boolean] = js.undefined, + // Options for tls.createSecureContext + var ca: js.UndefOr[SecureData] = js.undefined, + var cert: js.UndefOr[SecureData] = js.undefined, + var sigalgs: js.UndefOr[String] = js.undefined, + var ciphers: js.UndefOr[String] = js.undefined, + var clientCertEngine: js.UndefOr[String] = js.undefined, + var crl: js.UndefOr[SecureData] = js.undefined, + var dphram: js.UndefOr[String | Buffer] = js.undefined, + var ecdhCurve: js.UndefOr[String] = js.undefined, + var honorCihperOrder: js.UndefOr[Boolean] = js.undefined, + var key: js.UndefOr[SecureData] = js.undefined, + var maxVersion: js.UndefOr[String] = js.undefined, + var minVersion: js.UndefOr[String] = js.undefined, + var passphrase: js.UndefOr[String] = js.undefined, + var pfx: js.UndefOr[SecureData | js.Array[SecureDataObjectForm]] = js.undefined, + var secureOptions: js.UndefOr[Int] = js.undefined, + var secureProtocol: js.UndefOr[String] = js.undefined, + var sessionIdContext: js.UndefOr[String] = js.undefined, + var IncomingMessage: js.UndefOr[js.Function] = js.undefined, + var ServerResponse: js.UndefOr[js.Function] = js.undefined +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/https/package.scala b/app/current/src/main/scala/io/scalajs/nodejs/https/package.scala index 97a592d06..b5e946cea 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/https/package.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/https/package.scala @@ -1,10 +1,12 @@ package io.scalajs.nodejs +import com.thoughtworks.enableIf import io.scalajs.nodejs.http.{RequestOptions, ServerResponse} import io.scalajs.util.PromiseHelper._ -import io.scalajs.nodejs +import io.scalajs.nodejs.url.URL import scala.concurrent.Future +import scala.scalajs.js.| /** * https package object @@ -37,15 +39,21 @@ package object https { */ @inline def requestFuture(options: RequestOptions): Future[ServerResponse] = { - promiseWithError1[nodejs.Error, ServerResponse](https.request(options, _)) + promiseCallback1[ServerResponse](https.request(options, _)) } /** * Makes a request to a secure web server. */ @inline - def requestFuture(url: String): Future[ServerResponse] = { - promiseWithError1[nodejs.Error, ServerResponse](https.request(url, _)) + def requestFuture(url: String | URL): Future[ServerResponse] = { + promiseCallback1[ServerResponse](https.request(url, _)) + } + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + @inline + def requestFuture(url: String | URL, options: RequestOptions): Future[ServerResponse] = { + promiseCallback1[ServerResponse](https.request(url, options, _)) } } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/net/ConnectOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/net/ConnectOptions.scala deleted file mode 100644 index 458a7a210..000000000 --- a/app/current/src/main/scala/io/scalajs/nodejs/net/ConnectOptions.scala +++ /dev/null @@ -1,8 +0,0 @@ -package io.scalajs.nodejs.net - -import scala.scalajs.js - -/** - * Connect Options - */ -class ConnectOptions(path: String = null, host: String = null, port: Integer = null) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/net/Net.scala b/app/current/src/main/scala/io/scalajs/nodejs/net/Net.scala index b68f735a8..aaf229bf8 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/net/Net.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/net/Net.scala @@ -77,15 +77,7 @@ trait Net extends IEventEmitter { * parameter will be added as a listener for the 'connect' event once. * @example net.createConnection(options[, connectListener]) */ - def createConnection(options: ConnectOptions, connectListener: js.Function): Socket = js.native - - /** - * A factory function, which returns a new net.Socket and automatically connects with the supplied options. - * The options are passed to both the net.Socket constructor and the socket.connect method. The connectListener - * parameter will be added as a listener for the 'connect' event once. - * @example net.createConnection(options[, connectListener]) - */ - def createConnection(options: ConnectOptions): Socket = js.native + def createConnection(options: ConnectOptions, connectListener: js.Function = js.native): Socket = js.native /** * @example net.createConnection(path[, connectListener]) diff --git a/app/current/src/main/scala/io/scalajs/nodejs/net/Server.scala b/app/current/src/main/scala/io/scalajs/nodejs/net/Server.scala index 47448d6bf..30258ab82 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/net/Server.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/net/Server.scala @@ -35,23 +35,7 @@ class Server() extends IEventEmitter { * It is not recommended to use this option once a socket has been sent to a child with child_process.fork(). * @example server.maxConnections */ - var maxConnections: Int = js.native - - /** - * Limits maximum incoming headers count, equal to 1000 by default. If set to 0 - no limit will be applied. - * @example server.maxHeadersCount - */ - var maxHeadersCount: Int = js.native - - /** - * The number of milliseconds of inactivity before a socket is presumed to have timed out. - * Note that the socket timeout logic is set up on connection, so changing this value only affects - * new connections to the server, not any existing connections. - * Set to 0 to disable any kind of automatic timeout behavior on incoming connections. - * Default = 120000 (2 minutes) - * @example server.timeout - */ - var timeout: Int = js.native + var maxConnections: js.UndefOr[Int] = js.native ///////////////////////////////////////////////////////////////////////////////// // Methods diff --git a/app/current/src/main/scala/io/scalajs/nodejs/net/package.scala b/app/current/src/main/scala/io/scalajs/nodejs/net/package.scala index 5200bae99..d0b1ec69e 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/net/package.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/net/package.scala @@ -11,6 +11,8 @@ import scala.scalajs.js */ package object net { + type ConnectOptions = http.ConnectionOptions + /** * net.Server Events * @param server the given [[Server server]] diff --git a/app/current/src/main/scala/io/scalajs/nodejs/stream/LegacyStream.scala b/app/current/src/main/scala/io/scalajs/nodejs/stream/LegacyStream.scala new file mode 100644 index 000000000..50bbe9883 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/stream/LegacyStream.scala @@ -0,0 +1,8 @@ +package io.scalajs.nodejs.stream + +import io.scalajs.nodejs.events.IEventEmitter + +import scala.scalajs.js + +@js.native +trait LegacyStream extends IEventEmitter diff --git a/app/current/src/main/scala/io/scalajs/nodejs/stream/Readable.scala b/app/current/src/main/scala/io/scalajs/nodejs/stream/Readable.scala index bcab9f7de..01c35da50 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/stream/Readable.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/stream/Readable.scala @@ -2,7 +2,6 @@ package io.scalajs.nodejs package stream import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.events.IEventEmitter import scala.scalajs.js @@ -12,7 +11,7 @@ import scala.scalajs.js * @see https://nodejs.org/api/stream.html#stream_readable_streams */ @js.native -trait Readable extends IEventEmitter { +trait Readable extends LegacyStream { ///////////////////////////////////////////////////////////////////////////////// // Properties diff --git a/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala b/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala index d6f9c6313..72779b403 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala @@ -2,12 +2,12 @@ package io.scalajs.nodejs package stream import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.events.IEventEmitter 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.| /** @@ -22,7 +22,7 @@ class WritableClass(options: WritableOptions = js.native) extends Writable * The Writable stream interface is an abstraction for a destination that you are writing data to. */ @js.native -trait Writable extends IEventEmitter { +trait Writable extends LegacyStream { ///////////////////////////////////////////////////////////////////////////////// // Internal Methods @@ -65,53 +65,12 @@ trait Writable extends IEventEmitter { */ def cork(): Unit = js.native - /** - * Call this method when no more data will be written to the stream. If supplied, the callback - * is attached as a listener on the 'finish' event. - * Calling stream.write() after calling stream.end() will raise an error. - * @param chunk The data to write ( | ) - * @param callback the Callback for when this chunk of data is flushed - * @example writable.end([chunk][, encoding][, callback]) - */ - def end(chunk: String | Buffer, callback: js.Function1[Error, Any]): Unit = js.native - - /** - * Call this method when no more data will be written to the stream. If supplied, the callback - * is attached as a listener on the 'finish' event. - * Calling stream.write() after calling stream.end() will raise an error. - * @param chunk The data to write ( | ) - * @example writable.end([chunk][, encoding][, callback]) - */ - def end(chunk: String | Buffer): Unit = js.native + def end(chunk: String | Uint8Array, callback: js.Function1[Error, Any]): Unit = js.native + def end(chunk: String | Uint8Array): Unit = js.native - /** - * Call this method when no more data will be written to the stream. If supplied, the callback - * is attached as a listener on the 'finish' event. - * Calling stream.write() after calling stream.end() will raise an error. - * @param chunk The data to write ( | ) - * @param encoding The encoding, if chunk is a String - * @example writable.end([chunk][, encoding][, callback]) - */ def end(chunk: String, encoding: String, callback: js.Function1[Error, Any]): Unit = js.native - - /** - * Call this method when no more data will be written to the stream. If supplied, the callback - * is attached as a listener on the 'finish' event. - * Calling stream.write() after calling stream.end() will raise an error. - * @param chunk The data to write ( | ) - * @param encoding The encoding, if chunk is a String - * @example writable.end([chunk][, encoding][, callback]) - */ - def end(chunk: String, encoding: String): Unit = js.native - - /** - * Call this method when no more data will be written to the stream. If supplied, the callback - * is attached as a listener on the 'finish' event. - * Calling stream.write() after calling stream.end() will raise an error. - * @param callback the Callback for when this chunk of data is flushed - * @example writable.end([chunk][, encoding][, callback]) - */ - def end(callback: js.Function1[Error, Any] = js.native): Unit = js.native + def end(chunk: String, encoding: String): Unit = js.native + def end(callback: js.Function1[Error, Any] = js.native): Unit = js.native /** * Sets the default encoding for a writable stream. @@ -125,34 +84,9 @@ trait Writable extends IEventEmitter { */ def uncork(): Unit = js.native - /** - * Flush all data, buffered since stream.cork() call. - * @param chunk The data to write ( | ) - * @param callback the Callback for when this chunk of data is flushed - * @return true, if the data was handled completely - * @example writable.write(chunk[, encoding][, callback]) - */ - def write(chunk: Buffer | String, callback: js.Function1[Error, Any] = js.native): Boolean = js.native - - /** - * Flush all data, buffered since stream.cork() call. - * @param chunk The data to write ( | ) - * @param encoding The encoding, if chunk is a String - * @return true, if the data was handled completely - * @example writable.write(chunk[, encoding][, callback]) - */ - def write(chunk: Buffer | String, encoding: String): Boolean = js.native - - /** - * Flush all data, buffered since stream.cork() call. - * @param chunk The data to write ( | ) - * @param encoding The encoding, if chunk is a String - * @param callback the Callback for when this chunk of data is flushed - * @return true, if the data was handled completely - * @example writable.write(chunk[, encoding][, callback]) - */ - def write(chunk: Buffer | String, encoding: String, callback: js.Function1[Error, Any]): Boolean = js.native - + def write(chunk: Uint8Array | String, callback: js.Function1[Error, Any] = js.native): Boolean = js.native + def write(chunk: String, encoding: String): Boolean = js.native + def write(chunk: String, encoding: String, callback: js.Function1[Error, Any]): Boolean = js.native } /** @@ -211,7 +145,7 @@ object Writable { /** * Writable Extensions */ - implicit class WritableExtensions[T <: Writable](val writable: T) extends AnyVal { + implicit final class WritableExtensions[T <: Writable](val writable: T) extends AnyVal { @inline def endFuture(chunk: Buffer): Future[Unit] = promiseWithError0[Error](writable.end(chunk, _)) @@ -225,10 +159,14 @@ object Writable { def endFuture(): Future[Unit] = promiseWithError0[Error](writable.end) @inline - def writeFuture(chunk: Buffer | String, encoding: String = null): Future[Unit] = { - promiseWithError0[Error](writable.write(chunk, encoding, _)) + def writeFuture(chunk: Uint8Array): Future[Unit] = { + promiseWithError0[Error](writable.write(chunk, _)) } + @inline + def writeFuture(chunk: String, encoding: String = null): Future[Unit] = { + promiseWithError0[Error](writable.write(chunk, encoding, _)) + } } } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/tls/SecureContextOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/tls/SecureContextOptions.scala new file mode 100644 index 000000000..3f35802cb --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/tls/SecureContextOptions.scala @@ -0,0 +1,26 @@ +package io.scalajs.nodejs.tls + +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js +import scala.scalajs.js.| + +class SecureContextOptions( + var ca: js.UndefOr[SecureData] = js.undefined, + var cert: js.UndefOr[SecureData] = js.undefined, + var sigalgs: js.UndefOr[String] = js.undefined, + var ciphers: js.UndefOr[String] = js.undefined, + var clientCertEngine: js.UndefOr[String] = js.undefined, + var crl: js.UndefOr[SecureData] = js.undefined, + var dphram: js.UndefOr[String | Buffer] = js.undefined, + var ecdhCurve: js.UndefOr[String] = js.undefined, + var honorCihperOrder: js.UndefOr[Boolean] = js.undefined, + var key: js.UndefOr[SecureData] = js.undefined, + var maxVersion: js.UndefOr[String] = js.undefined, + var minVersion: js.UndefOr[String] = js.undefined, + var passphrase: js.UndefOr[String] = js.undefined, + var pfx: js.UndefOr[SecureData | js.Array[SecureDataObjectForm]] = js.undefined, + var secureOptions: js.UndefOr[Int] = js.undefined, + var secureProtocol: js.UndefOr[String] = js.undefined, + var sessionIdContext: js.UndefOr[String] = js.undefined +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/tls/ServerOptions.scala b/app/current/src/main/scala/io/scalajs/nodejs/tls/ServerOptions.scala new file mode 100644 index 000000000..76ce82737 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/tls/ServerOptions.scala @@ -0,0 +1,41 @@ +package io.scalajs.nodejs.tls + +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js +import scala.scalajs.js.typedarray.{DataView, TypedArray} +import scala.scalajs.js.| + +class ServerOptions( + var ALPNProtocols: js.UndefOr[ + js.Array[String] | js.Array[TypedArray[_, _]] | js.Array[DataView] | TypedArray[_, _] | DataView + ] = js.undefined, + var enableTrace: js.UndefOr[Boolean] = js.undefined, + var handshakeTimeout: js.UndefOr[Int] = js.undefined, + var rejectUnauthorized: js.UndefOr[Boolean] = js.undefined, + var requestCert: js.UndefOr[Boolean] = js.undefined, + var sessionTimeout: js.UndefOr[Int] = js.undefined, + var SNICallback: js.UndefOr[js.Function2[String, js.Function2[io.scalajs.nodejs.Error, SecureContext, Any], Any]], + var ticketKeys: js.UndefOr[Buffer] = js.undefined, + // Options for net.createServers + val allowHalfOpen: js.UndefOr[Boolean] = js.undefined, + val pauseOnConnect: js.UndefOr[Boolean] = js.undefined, +// Options for tls.createSecureContext + var ca: js.UndefOr[SecureData] = js.undefined, + var cert: js.UndefOr[SecureData] = js.undefined, + var sigalgs: js.UndefOr[String] = js.undefined, + var ciphers: js.UndefOr[String] = js.undefined, + var clientCertEngine: js.UndefOr[String] = js.undefined, + var crl: js.UndefOr[SecureData] = js.undefined, + var dphram: js.UndefOr[String | Buffer] = js.undefined, + var ecdhCurve: js.UndefOr[String] = js.undefined, + var honorCihperOrder: js.UndefOr[Boolean] = js.undefined, + var key: js.UndefOr[SecureData] = js.undefined, + var maxVersion: js.UndefOr[String] = js.undefined, + var minVersion: js.UndefOr[String] = js.undefined, + var passphrase: js.UndefOr[String] = js.undefined, + var pfx: js.UndefOr[SecureData | js.Array[SecureDataObjectForm]] = js.undefined, + var secureOptions: js.UndefOr[Int] = js.undefined, + var secureProtocol: js.UndefOr[String] = js.undefined, + var sessionIdContext: js.UndefOr[String] = js.undefined +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/tls/TLSSocket.scala b/app/current/src/main/scala/io/scalajs/nodejs/tls/TLSSocket.scala index c974d5b47..00d5fca7d 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/tls/TLSSocket.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/tls/TLSSocket.scala @@ -75,5 +75,5 @@ class TLSSocketOptions(val isServer: js.UndefOr[Boolean] = js.undefined, val SNICallback: js.UndefOr[Boolean] = js.undefined, val session: js.UndefOr[Buffer] = js.undefined, val requestOCSP: js.UndefOr[Boolean] = js.undefined, - val secureContext: js.UndefOr[js.Any] = js.undefined) + val secureContext: js.UndefOr[SecureContext] = js.undefined) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/tls/Tls.scala b/app/current/src/main/scala/io/scalajs/nodejs/tls/Tls.scala index f50760be4..3513a599e 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/tls/Tls.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/tls/Tls.scala @@ -22,6 +22,8 @@ trait Tls extends js.Object { */ def connect(port: Int, host: String, options: TlsConnectOptions, callback: js.Function): Unit = js.native + def createSecureContext(options: SecureContextOptions = js.native): SecureContext = js.native + } /** diff --git a/app/current/src/main/scala/io/scalajs/nodejs/tls/package.scala b/app/current/src/main/scala/io/scalajs/nodejs/tls/package.scala new file mode 100644 index 000000000..42f7a85cc --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/tls/package.scala @@ -0,0 +1,14 @@ +package io.scalajs.nodejs + +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js +import scala.scalajs.js.| + +package object tls { + type SecureContext = js.Any + + type SecureData = String | js.Array[String] | Buffer | js.Array[Buffer] + + type SecureDataObjectForm = js.Object +} diff --git a/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/HttpTest.scala b/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/HttpTest.scala index 1dc7efbd8..3a7cf909a 100644 --- a/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/HttpTest.scala +++ b/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/HttpTest.scala @@ -26,6 +26,11 @@ class HttpTest extends FunSpec { //setTimeout(() => server.close(), 100.millis) } + + it("should provide statusCode") { + assert(Http.STATUS_CODES.`403` === "Forbidden") + assert(Http.STATUS_CODES.`500` === "Internal Server Error") + } } } diff --git a/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/StatusCodeTest.scala b/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/StatusCodeTest.scala new file mode 100644 index 000000000..50cd8cfd4 --- /dev/null +++ b/app/nodejs-v8/src/test/scala/io/scalajs/nodejs/http/StatusCodeTest.scala @@ -0,0 +1,30 @@ +package io.scalajs.nodejs.http + +import org.scalatest.FunSpec + +import scala.scalajs.js + +/** + * Http Tests + */ +class StatusCodeTest extends FunSpec { + + describe("Http") { + + it("should provide an HTTP server") { + + val server = Http.createServer((request: ClientRequest, response: ServerResponse) => { + response.writeHead(statusCode = 200, headers = js.Dictionary("Content-Type" -> "text/plain")) + response.write("Hello World") + response.end() + }) + assert(server !== null) + + // don't listen on a port + //server.listen(58888) + //setTimeout(() => server.close(), 100.millis) + + } + } + +}