Giter Site home page Giter Site logo

building42 / telegraph Goto Github PK

View Code? Open in Web Editor NEW
771.0 18.0 122.0 1.36 MB

Secure Web Server for iOS, tvOS and macOS

License: MIT License

Ruby 0.44% Swift 98.03% Objective-C 0.27% HTML 0.27% Shell 0.98%
swift secure webserver websocket https ssl certificate telegraph ios tvos macos

telegraph's Introduction

Telegraph: Secure Web Server for iOS, tvOS and macOS

Telegraph CI CocoaPods compatible License Platform

Telegraph is a Secure Web Server for iOS, tvOS and macOS written in Swift.

Features

  • Handles HTTP 1.0/1.1 requests
  • Secure traffic, HTTPS/TLS encryption
  • WebSocket client and server
  • Uses well tested socket library CocoaAsyncSocket
  • Uses performant low memory HTTP parser library llhttp
  • Customizable, from time-outs to message handlers
  • Simple, well commented code

Platforms

  • iOS 12.0+
  • tvOS 12.0+
  • macOS 10.13+

Installation

Swift Package Manager

The Swift Package Manager is a tool for automating the distribution of Swift code.

You can add Telegraph to your project by choosing the File - Swift Packages - Add Package Dependency option. Use the repository url as specified below and select the version you want to use.

Or you can manually add a Package.swift file to your project with:

dependencies: [
    .package(url: "https://github.com/Building42/Telegraph.git")
]

CocoaPods

CocoaPods is a dependency manager for Cocoa projects that makes dependencies a part of your workspace.

pod 'Telegraph'

See CocoaPods - Getting Started for more information.

Build

You can build the Telegraph framework and the examples with these steps:

  1. clone the repository
  2. open Telegraph.xcworkspace
  3. make sure that Xcode downloads the Swift Package Dependencies
  4. select one of the example schemes and build

This is only necessary if you want to make changes to the framework or try out the examples.

Usage

Configure App Transport Security

With iOS 9 Apple introduced APS (App Transport Security) in an effort to improve user security and privacy by requiring apps to use secure network connections over HTTPS. It means that without additional configuration unsecure HTTP requests in apps that target iOS 9 or higher will fail. In iOS 9, APS is unfortunately also activated for LAN connections. Apple fixed this in iOS 10, by adding NSAllowsLocalNetworking.

Even though we are using HTTPS, we have to consider the following:

  1. when we are communicating between iPads, it is likely that we'll connect on IP addresses, or at least that the hostname of the device won't match the common name of the certificate.
  2. our server will use a certificate signed by our own Certificate Authority instead of a well recognized root Certificate Authority.

You can disable APS by adding the key App Transport Security Settings to your Info.plist, with a sub-key where Allow Arbitrary Loads is set to Yes. For more information see ATS Configuration Basics.

Prepare the certificates

For a secure web server you'll need two things:

  1. one or more Certificate Authority certificates in DER format.
  2. a PKCS12 bundle containing a private key and certificate (signed by the CA)

Telegraph contains classes to make it easier to load the certificates:

let caCertificateURL = Bundle.main.url(forResource: "ca", withExtension: "der")!
let caCertificate = Certificate(derURL: caCertificateURL)!

let identityURL = Bundle.main.url(forResource: "localhost", withExtension: "p12")!
let identity = CertificateIdentity(p12URL: identityURL, passphrase: "test")!

Note: macOS doesn't accept P12 files without passphrase.

HTTP: Server

You most likely want to create a secure server by passing in the certificates:

serverHTTPs = Server(identity: identity, caCertificates: [caCertificate])
try! server.start(port: 9000)

Or for a quick test, create an unsecure server:

serverHTTP = Server()
try! server.start(port: 9000)

You can limit the server to localhost connections by specifying an interface when you start it:

try! server.start(port: 9000, interface: "localhost")

HTTP: Routes

Routes consist of three parts: HTTP method, path and a handler:

server.route(.POST, "test", handleTest)
server.route(.GET, "hello/:name", handleGreeting)
server.route(.GET, "secret/*") { .forbidden }
server.route(.GET, "status") { (.ok, "Server is running") }

server.serveBundle(.main, "/")

// You can also serve custom urls, for example the Demo folder in your bundle
let demoBundleURL = Bundle.main.url(forResource: "Demo", withExtension: nil)!
server.serveDirectory(demoBundleURL, "/demo")

Slashes at the start of the path are optional. Routes are case insensitive. You can specify custom regular expressions for more advanced route matching. When none of the routes are matched, the server will return a 404 not found.

The first route in the example above has a route parameter (name). When the server matches the incoming request to that route it will place the parameter in the params array of the request:

func handleGreeting(request: HTTPRequest) -> HTTPResponse {
  let name = request.params["name"] ?? "stranger"
  return HTTPResponse(content: "Hello \(name.capitalized)")
}

HTTP: Middleware

When a HTTP request is handled by the Server it is passed through a chain of message handlers. If you don't change the default configuration, requests will first be passed to the HTTPWebSocketHandler and then to the HTTPRouteHandler.

Below is an example of a message handler:

public class HTTPGETOnlyHandler: HTTPRequestHandler {
  public func respond(to request: HTTPRequest, nextHandler: HTTPRequest.Handler) throws -> HTTPResponse? {
    // If this is a GET request, pass it to the next handler
    if request.method == .GET {
      return try nextHandler(request)
    }

    // Otherwise return 403 - Forbidden
    return HTTPResponse(.forbidden, content: "Only GET requests are allowed")
  }
}

You can enable the message handler by setting it in the HTTP configuration:

server.httpConfig.requestHandlers.insert(HTTPGETOnlyHandler(), at: 0)

Note that the order of the request handlers is important. You'll probably want to have the HTTPRouteHandler as the last request handler or your Server won't handle any route requests. The HTTPRouteHandler doesn't call any handlers, so don't specify any handlers after the HTTPRouteHandler.

You can also modify the request in handlers. This handler copies the QueryString items into the request's params dictionary:

public class HTTPRequestParamsHandler: HTTPRequestHandler {
  public func respond(to request: HTTPRequest, nextHandler: HTTPRequest.Handler) throws -> HTTPResponse? {
    // Extract the query string items and put them in the HTTPRequest params
    request.uri.queryItems?.forEach { item in
      request.params[item.name] = item.value
    }

    // Continue with the rest of the handlers
    return try nextHandler(request)
  }
}

But what if you want to add headers to a response? Simply call the chain and modify the result:

public class HTTPAppDetailsHandler: HTTPRequestHandler {
  public func respond(to request: HTTPRequest, nextHandler: HTTPRequest.Handler) throws -> HTTPResponse? {
    //  Let the other handlers create a response
    let response = try nextHandler(request)

    // Add our own bit of magic
    response.headers["X-App-Version"] = "My App 1.0"
    return response
  }
}

HTTP: Cross-Origin Resource Sharing (CORS)

The CORS mechanism controls which sites will have permission to access the resources of your server. You can set CORS by sending the Access-Control-Allow-Origin header to the client. For development purposes it can be useful to allow all sites with the * value.

response.headers.accessControlAllowOrigin = "*"

If you want to make it a bit fancier, you can create a handler:

public class HTTPCORSHandler: HTTPRequestHandler {
  public func respond(to request: HTTPRequest, nextHandler: HTTPRequest.Handler) throws -> HTTPResponse? {
    let response = try nextHandler(request)

    // Add access control header for GET requests
    if request.method == .GET {
      response?.headers.accessControlAllowOrigin = "*"
    }

    return response
  }
}

For increased security you can add additional checks, dig down into the request, and send back different CORS headers for different clients.

HTTP: Client

For client connections we'll use Apple's URLSession class. Ray Wenderlich has an excellent tutorial on it. We're going to have to manually verify the TLS handshake (App Transport Security needs to be disabled for this):

let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
let tlsPolicy = TLSPolicy(commonName: "localhost", certificates: [caCertificate])

extension YourClass: URLSessionDelegate {
  func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
      completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    // The TLSPolicy class will do most of the work for us
    let credential = tlsPolicy.evaluateSession(trust: challenge.protectionSpace.serverTrust)
    completionHandler(credential == nil ? .cancelAuthenticationChallenge : .useCredential, credential)
  }
}

The common name in the TLSPolicy should match the common name of the certificate of the server (that was provided in the P12 archive). Although I don't recommend it, you can disable the common name check by providing an empty string (if you provide nil, the common name will be compared to the device's hostname).

For the common name you aren't limited to the hostname or IP address of the device. Your backend could, for example, generate a certificate with a common name that matches the UUID of the device. If the client knows the UUID of device it is connecting to, you could make it part of the TLSPolicy check.

WebSockets: Server-side

Your Server will automatically recognize WebSocket requests, thanks to the HTTPWebSocketHandler that is by default in the list of HTTP request handlers. Set the WebSocket delegate to handle incoming messages:

server.webSocketDelegate = self

Next step is to implement the ServerWebSocketDelegate methods:

func server(_ server: Server, webSocketDidConnect webSocket: WebSocket, handshake: HTTPRequest) {
  // A web socket connected, you can extract additional information from the handshake request
  webSocket.send(text: "Welcome!")
}

func server(_ server: Server, webSocketDidDisconnect webSocket: WebSocket, error: Error?) {
  // One of our web sockets disconnected
}

func server(_ server: Server, webSocket: WebSocket, didReceiveMessage message: WebSocketMessage) {
  // One of our web sockets sent us a message
}

func server(_ server: Server, webSocket: WebSocket, didSendMessage message: WebSocketMessage) {
  // We sent one of our web sockets a message (often you won't need to implement this one)
}

WebSockets: Middleware

Web sockets can have custom handlers too, although instead of a whole chain of handlers you specify a single class. The WebSocketMessageDefaultHandler will respond to connection-close messages and handle ping messages.

I recommend creating custom handlers by inheriting from the default handler:

public class AwesomeWebSocketHandler: WebSocketMessageHandler {
  public func incoming(message: WebSocketMessage, from webSocket: WebSocket) throws {
    // Don't forget to call super (for ping-pong etc.)
    super.incoming(message: message, from: webSocket)

    // Echo incoming text messages
    switch message.payload {
    case let .text(text): webSocket.send(text: text)
    default: break
    }
  }
}

WebSockets: Client-side

Now that we have a secure WebSocket server, we can use a secure WebSocket client as well by passing the CA certificate. Note that you only have to specify the CA certificate if the certificate isn't a root CA trusted by Apple or if you want to benefit from certificate pinning.

client = try! WebSocketClient("wss://localhost:9000", certificates: [caCertificate])
client.delegate = self

// You can specify headers too
client.headers.authorization = "Bearer secret-token"

The delegate methods look like this:

func webSocketClient(_ client: WebSocketClient, didConnectToHost host: String) {
  // The connection starts off as a HTTP request and then is upgraded to a
  // web socket connection. This method is called if the handshake was succesful.
}

func webSocketClient(_ client: WebSocketClient, didDisconnectWithError error: Error?) {
  // We were disconnected from the server
}

func webSocketClient(_ client: WebSocketClient, didReceiveData data: Data) {
  // We received a binary message. Ping, pong and the other opcodes are handled for us.
}

func webSocketClient(_ client: WebSocketClient, didReceiveText text: String) {
  // We received a text message, let's send one back
  client.send(text: "Message received")
}

FAQ

Why Telegraph?

There are only a few web servers available for iOS and many of them don't have SSL support. Our main goal with Telegraph is to offer secure HTTP and Web Socket traffic between iPads. The name is a tribute to the electrical telegraph, the first form of electrical telecommunications.

How do I create the certificates?

Basically what you want is a Certificate Authority and a Device certificate signed by that authority. You can find a nice tutorial at: https://jamielinux.com/docs/openssl-certificate-authority/

See the Tools folder for a script that can create self-signed certificates for you. The script is very basic and you will probably need to edit some information in the config-ca.cnf and config-localhost.cnf files. The certificates generated with the script are meant for development purposes only.

Why aren't my certificates working on iOS 13 or macOS 10.15 (or later)?

Apple has introduced new security requirements with iOS 13 and macOS 10.15. For more information see: https://support.apple.com/en-us/HT210176

My server isn't working properly

Please check the following:

  1. is Application Transport Security disabled?
  2. are your certificates valid?
  3. are your routes valid?
  4. have you customized any handlers? Is the route handler still included?

Have a look at the example project in this repository for a working starting point.

My browser doesn't display images from my bundle

During the build of your project Apple tries to optimize your images to reduce the size of your bundle. This optimization process sometimes causes the images to become unreadable by Chrome. Test your image url in Safari to double check if this is the case.

To solve this you can go to the property inspector in Xcode and change the type of the resource from Default - PNG image to Data. After that the build process won't optimize your file. I've also done this with logo.png in the example projects.

If you want to reduce the size of your images, I highly recommend ImageOptim.

Why can't I use port 80 and 443?

The first 1024 port numbers are restricted to root access only and your app doesn't have root access on the device. If you try to open a Server on those ports you will get a permission denied error when you start the server. For more information, read why are the first 1024 ports restricted to the root user only.

What if the device goes on standby?

If your app is send to the background or if the device goes on standby you typically have about 3 minutes to handle requests and close connections. You can create a background task with UIApplication.beginBackgroundTask to let iOS know that you need extra time to complete your operations. The property UIApplication.shared.backgroundTimeRemaining tells you the time that is left until a possible forced-kill of your app.

What about HTTP/2 support?

Ever wondered how the remote server knows that your browser is HTTP/2 compatible? During TLS negotiation, the application-layer protocol negotiation (ALPN) extension field contains "h2" to signal that HTTP/2 is going be used. Apple doesn't offer any (public) methods in Secure Transport or CFNetwork to configure ALPN extensions. A secure HTTP/2 iOS implementation is therefor not possible at the moment.

Can I use this in my Objective-C project?

This library was written in Swift and for performance reasons I haven't decorated classes with NSObject unless absolutely necessary (no dynamic dispatch). If you are willing to add Swift code to your project, you can integrate the server by adding a Swift wrapper class that inherits from NSObject and has a Telegraph Server variable.

Authors

This library was created by:

Code and design was inspired by:

Thank you to our contributors, your pull requests are most welcome and appreciated!

License

Telegraph is released under the MIT license. See LICENSE for details.

telegraph's People

Contributors

dabuddha avatar didi25 avatar geroherkenrath avatar harrisg avatar jedmartin93 avatar joebayld avatar kaden-weber avatar mbalex99 avatar opera-ddrechny avatar pikuseru avatar tadija avatar tomashubelbauer avatar vernadsky avatar yvbeek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

telegraph's Issues

how to set 'Location' header in the response to achieve http-redirection

I wanted this server (IOSExample) to redirect the calling user agent to get redirected. So while sending the response, I would like to insert 'headers' (2nd argument) with Location : "www.google.com". I am not able to find the correct way of coding it.

I tried the below any but response.headers.location = "www.google.com"; code is crashing with SIGABRT.

Can you please throw some light on what I am doing wrong ?

Thank you

Telegraphdemo.swift

extension TelegraphDemo {
  /// Raised when the /redirect enpoint is called
  private func redirectHandle(request: HTTPRequest) -> HTTPResponse {
    let response = HTTPResponse(HTTPStatus(code:302, phrase:"Found"), content: "Hello you got redirected")
    response.headers.location = "www.google.com";
    return response;
  }  
}

I added location to...

HTTPHeaders.swift

extension HTTPHeaderName {
  static let location = HTTPHeaderName("Location")
}

extension Dictionary where Key == HTTPHeaderName, Value == String {
  public var location: String? {
    get { return self[.location] }
    set { self[.location] = newValue }
  }
}

and those for other headers..

Processing POST with JSON data

I’m testing Telegraph in a MAC OS app and want the server to process a POST with data, like this from curl:

$ curl -X POST
    -H "Content-Type: application/json"
    -d ‘{“unit”:”testunit”,”data”:{“name”:”mydata”,”thedata”:”100”}}’
    https://localhost:9000/api -k

Routing seems to work fine, but In trying to convert the HTTPRequest body to a Swift dictionary, I’m not able to parse the data to that end. Is it possible to do this with Telegraph and if so, any examples?

Not able to run IOS Example app on iPhone,iphone crashes

I followed all the steps:
Able to run the IOS Example on iPhone simulator, and test https://localhost:9000.
However, when I change the target to IOS device that I have ( my iPhone 6S Plus, with IOS 12.1),
Xcode says my app is running, but the app is crashing as the debug windows of Xcode says.
perhaps, the app is open on iPhone, but it does not respond to any http request as the code had crashed.

Can you please help me to see what I am missing. I am new to IOS dev, intact this is my first app I am playing with...

dyld: Library not loaded: @rpath/Telegraph.framework/Telegraph
  Referenced from: /var/containers/Bundle/Application/C43E1AB1-6776-48B2-BDE9-47CA4B827A7C/iOS Example.app/iOS Example
  Reason: image not found

Ajax Calls?

Using this https server to make ajax calls?

Basic unsecured server not working

When I use the demo that comes with Telegraph the server starts and works perfectly, however when I try to just test an unsecured server it doesn't work.

The demo code that works:

server = Server(identity: identity, caCertificates: [caCertificate])
server.webSocketConfig.pingInterval = 10
server.webSocketDelegate = self

// Define the demo routes
server.route(.get, "hello/:name", serverHandleGreeting)
server.route(.get, "hello(/)", serverHandleGreeting)
server.route(.get, "secret/*") { .forbidden }
server.route(.get, "status") { (.ok, "Server is running") }
server.serveBundle(.main, "/")
    
// Start the server on localhost, we'll skip error handling for the demo
// Note: if you test in your browser, don't forget to type https://
try! server.start(onPort: 9000)
serverLog("Server is running at https://localhost:9000")

My test of a basic server that doesn't work:

let server = Server()      
server.route(.get, "status") { (.ok, "Server is running") }
        
try! server.start(onPort: 9000)

cant access to server from local

Hi,

I did install Telegraph by pod, and then in application: didFinishLaunchingWithOptions. I have:

let server = Server()
try! server.start(onInterface: "localhost", port: 9000)
		
server.route(.get, "status") { () -> HTTPResponse in
   return HTTPResponse(.ok, content: "server is running")
}

server.serveBundle(.main, "/")

but I dont know how to access localhost:9000 from my browser or simulator browser.

What I really need is: to have an app that work as a server and an other app that send request and show data, so I'm gonna need to call my server from outside. how can I do that ?

CLI Support?

I tried building a quick and dirty console application using Telegraph and I couldn't get any of the dependencies working. Is this a Swift limitation or one with Telegraph? I was able to make one just fine as a regular .app.

Maybe put a sample CLI application using Telegraph?

I am writing a REST service that requires SSL so I chose this framework and I want to compile it down to a CLI application and not a .app.

Thanks!

Add tvOS Support

I saw this project linked from #httpswift/swifter#111 and I love that it supports SSL.

I was hoping this project would have compatibility with tvOS to run a web server on the Apple TV. However, the Cocoapods installation reads:

[!] The platform of the target TVMLCatalog (tvOS 9.0) is not compatible with Telegraph (0.1.0), which does not support tvos.

I'm not sure if it'd be easy enough to add this to the supported platforms list, or if it would require more work. tvOS and iOS should share much of their functionality, so there's less of a gap than say with macOS.

not work on the device

v0.21,i created a webService in my app, transfer file from PC to my app on the same wifi.
It's all right on the simulator, but it's going to go wrong on the real device, can not open index.html on my pc,always show me time out,and no error was logged at the console.

can not connect with other platform Websocker Server or Client (AndroidAsync)

I run the demo Telegraph provided, it is ok. I use two iPhones, one is server and one is client, that is ok, too. But I use one iPhone as WebSocket server, one Android phone as WebSocket client (using AndroidAsync), the server did not run normally. If iPhone as WebSocket client, android phone as server, the client did not run normally. I think maybe Telegraph handles something unproperly.

Sorry for my poor English.

Add Mac Support (with Carthage)?

Hey!

I'd like to use this project (since it supports HTTPS and I like that) in a mac app. I'm also using Carthage. I started working on adding mac support to see if it worked (it does) but I wanted to check with you before opening a pull request.

Basically that means:

  • Adding a mac framework target so it works with Carthage
  • Updating the Podfile and the podspec
  • Adding a sample app for mac

If that's something you're comfortable with, I'll open a PR later this week.

How to tell serverBundle which subdirectory to use?

Hello, I am trying to serve contents of my www directory which I created by dragging a directory within the projects folder structure from Finder to Xcode project node and selecting the directory references option as opposed to creating a new group.

The code I am using is as follows:

server = Server()
server.serveBundle(.main, "/", index: "/www/index.html")
server.route(.get, "status") { (.ok, "Server is running") }
try! server.start(onPort: 80)

I am able to access http://192.168.0.whatever/ and see the contents of www/index.html displayed in Chrome, but requests to collocated resource files (like index.js which is next to index.html in www) fail. Accessing /www/index.js works.

I know I need to change the bundle from .main to something else which tells the route what to use as a root, but I am unsure how. Using:

server.serveBundle(Bundle(path: "www")!, "/")

...compiles, but it doesn't work, the browser still receives a network error when accessing /.

Low speed. Large image loads really slowly.

In my app I serve temp directory which contains large images from camera roll and html file which displays these images using <img src='...'>. Loading of one image takes around 5s so it is really slow. Shouldn't it be fast while we're using local wifi ? Is there any way to speed it up?

WebSocket pinginterval causes websocket stuck

Hi, I'm Riccardo, thank you for this awesome library.
I've setup web server exactly like in your example. My iOS app is a websocket server, so i implemented ServerWebSocketDelegate delegate methods.
My websocket client is a simple javascript.
The problem is that after ping-pong-ping between client/server (and some text messages) websocket channel get stuck. Last pong is not received e no more text messages are sent/received through the channel.
This is the log:

server(_:webSocketDidConnect:handshake:)
WebSocket connected (http://ws-example:8888)
server(_:webSocket:didSendMessage:)
WebSocket sent message: <WebSocketMessage: 0x000000016d4da358, opcode: textFrame, payload: 'Welcome from iOS APP!'>
server(_:webSocket:didReceiveMessage:)
WebSocket received message: <WebSocketMessage: 0x000000016d4da358, opcode: textFrame, payload: 'HELLO FROM JS CLIENT!'>
server(_:webSocket:didSendMessage:)
WebSocket sent message: <WebSocketMessage: 0x000000016d4da358, opcode: ping, payload: none>
server(_:webSocket:didReceiveMessage:)
WebSocket received message: <WebSocketMessage: 0x000000016d4da358, opcode: pong, payload: none>
server(_:webSocket:didSendMessage:)
WebSocket sent message: <WebSocketMessage: 0x000000016d4da358, opcode: ping, payload: none>

If i set server.webSocketConfig.pingInterval = 0 all works fine, because no ping-pong is sent/received. With pingInterval = 0 channel goes closed after one minute, but in this minute all text messages are correctly delivered.
Here is my JS code:

window.onload = function() {

  // Get references to elements on the page.
  var form = document.getElementById('message-form');
  var messageField = document.getElementById('message');
  var messagesList = document.getElementById('messages');
  var socketStatus = document.getElementById('status');
  var closeBtn = document.getElementById('close');
  // Create a new WebSocket.
  var socket = new WebSocket('wss://192.168.1.37:9000');
  // Handle any errors that occur.
  socket.onerror = function(error) {
    console.log('WebSocket Error: ' + JSON.stringify(error));
  };
  // Show a connected message when the WebSocket is opened.
  socket.onopen = function(event) {
    socketStatus.innerHTML = 'Connected to: ' + event.currentTarget.url;
    socketStatus.className = 'open';
  };
  // Handle messages sent by the server.
  socket.onmessage = function(event) {
    var message = event.data;
    messagesList.innerHTML += '<li class="received"><span>Received:</span>' +
                               message + '</li>';
  };
  // Show a disconnected message when the WebSocket is closed.
  socket.onclose = function(event) {
    socketStatus.innerHTML = 'Disconnected from WebSocket.';
    socketStatus.className = 'closed';
  };
  // Send a message when the form is submitted.
  form.onsubmit = function(e) {
    e.preventDefault();
    // Retrieve the message from the textarea.
    var message = messageField.value;
    // Send the message through the WebSocket.
    socket.send(message);
    // Add the message to the messages list.
    messagesList.innerHTML += '<li class="sent"><span>Sent:</span>' + message +
                              '</li>';
    // Clear out the message field.
    messageField.value = '';
    return false;
  };
  // Close the WebSocket connection when the close button is clicked.
  closeBtn.onclick = function(e) {
    e.preventDefault();
    // Close the WebSocket.
    socket.close();
    return false;
  };
};

Thank you!

The header (Sec-WebSocket-Protocol) is not returned to the client on the real device

v0.18, websocketserver module. client: chrome
It's all right on the emulator, but it's going to go wrong on the real device, getting Sec-WebSocket-Protocol headers empty strings on the client side
error:

WebSocket connection to 'ws://192.168.199.165:9001/asdf' failed: Error during WebSocket handshake: 'Sec-WebSocket-Protocol' header value '' in response does not match any of sent values

request:

Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7
Cache-Control: no-cache
Connection: Upgrade
Host: 192.168.199.165:9001
Origin: http://localhost:63342
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: Nj31L7B8S9YgQmorv/Zi8Q==
Sec-WebSocket-Protocol: sub
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

response:

Connection: Upgrade
Date: Thu, 01 Nov 2018 06:38:37 GMT
Sec-WebSocket-Accept: N872DmYyQlTZNYZnTzQEzOhWWZs=
Sec-WebSocket-Protocol:
Upgrade: websocket

p12 certs on Mac OS X 10.11

No clue if it's just me but on my local machine which is running 10.12 I can load the .p12 cert just fine. The same cert causes our test machine which runs 10.11 to blow up pretty spectacularly. I've even tried generating new certs on that machine and it still blows up.

I looked at the return code I get and it's errSecInteractionNotAllowed from SecPKCS12Import. I'm running this via SSH. I'm using sudo though, so you would think it would have access to the keychain.

How do check if the server is running?

Hi there,

Very quick question as I can't seem to find anything obvious like this in the API.

How can I quickly check if the server is actually running? I'd expect a simple method like: isServing / isRunning etc to exist.

Cheers,
Matt

How to serve Temporary directory?

I have tried:
server.serveDirectory(URL(string: NSTemporaryDirectory())!) server.serveDirectory(URL(fileURLWithPath: NSTemporaryDirectory()))
but nothing works. I managed to serve main bundle, but I cannot serve Temp. Please help :)

Always trust certificates?

I generated the .ca and .der files following the tutorial you linked to and when I start the application the first request creates a pop-up on the server to trust the certificate. I have clicked "Allow Always" and I've also added the certificate authority and the certificate to the keystone and set it to "Always Trust" and I still get the pop-up. This is on Mac OS X. Anyway to prevent that? I'm afraid when the server reboots someone won't be around to click that dialog.

Objective-C project support

My project base on Objc. I want to use this framework. I import Telegraph-Swift.h to my file, but only few class had convert to objc. I can not user most of the swift classes.

Can anybody impove this?

Swift language runtime "Simultaneous accesses to ..., but modification requires exclusive access."

Hi guys,

Just have started using your great framework. It's awesome! Thanks for your great work!

When I create a new project in Xcode 9.1, pod Telegraph and even just copy-pasted your iOS example and try to run, there are Swift language runtime warnings in console pointing to different parts of HTTPParser.

When I'm trying your bundled sample from Telegraph.xcworkspace there's no such issue at all.

Is it some Xcode 9 settings? Please, suggest.
screen shot 2017-11-05 at 17 46 37

iOS8 support?

My app should support iOS8, , but Telegraph did not support ios8.0. i should how to do?

Websocket ping/pong cause crash

Hi Zyphrax,
sorry but I updated Xcode to 9.1 (9B55) and Swift 4.0.2 and ping pong crashes again.
When the first pong is received from client app crashes. See stacktrace here.
32329146-65afee76-bfdc-11e7-9796-0dc45ed00a6b

Safari: Invalid certificate chain

I am having this issue with Safari: WebSocket network error: OSStatus Error -9807: Invalid certificate chain. It only happens on Safari when I try to connect to a wss.

Thanks!

Latest commits broke Carthage build

Since the last few commits, Carthage build fails with message:

*** Building scheme "Telegraph iOS" in Telegraph.xcworkspace
Build Failed
	Task failed with exit code 65:
	/usr/bin/xcrun xcodebuild -workspace /Users/milanstevanovic/Developer/Stocks/ios-stocks/Carthage/Checkouts/Telegraph/Telegraph.xcworkspace -scheme Telegraph\ iOS -configuration Release -derivedDataPath /Users/milanstevanovic/Library/Caches/org.carthage.CarthageKit/DerivedData/9.2_9C40b/Telegraph/451adbef4505ee20f10920c1f705f831f449221d -sdk iphoneos ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= CARTHAGE=YES archive -archivePath /var/folders/77/v4xtnv9j7sxbvplzq1ln4yvc0000gn/T/Telegraph SKIP_INSTALL=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=NO CLANG_ENABLE_CODE_COVERAGE=NO STRIP_INSTALLED_PRODUCT=NO (launched in /Users/milanstevanovic/Developer/Stocks/ios-stocks/Carthage/Checkouts/Telegraph)

This usually indicates that project itself failed to compile. Please check the xcodebuild log for more details: /var/folders/77/v4xtnv9j7sxbvplzq1ln4yvc0000gn/T/carthage-xcodebuild.lYBhpZ.log

Contents of the log file:
carthage-xcodebuild.lYBhpZ.log

Http connections closes after a while

Hi :)
The library is great, everything works well thanks !
But, after a while (i.e 10 minutes) leaving the server on (an iPad) with a socket connection open (by calling server.start(onPort:), the other devices cannot connect the server anymore.

If I restart the server (stop then start), the connection comes back. II tried putting a timer that restarts the server periodically but this is not a perfect solution since after some tests some client requests fail when they happen at the wrong moment during the restart (even if I call server.stop(immediately: false) )

Is it something that you are aware of ? Is there a best practice I did not get ?

Thanks a lot :)

Bonjour registration and issuing a certificate for the Bonjour hostname

Hello, please entertain my noob question, but I was wondering whether there is support planned for the Bonjour registration so that my embedded web server instance can be accessed over a proper hostname (like http://tomas-hubelbauer.local which I got with GCDWebServer) and not just an IP address.

Additionally, do you think it would be possible to issue an Let's Encrypt SSL certificate for that Bonjour hostname as a domain name (will there be a problem with local not being a real TLD?) so that I can have a certificate that is trusted by the browser without uploading a new root certificate?

Thanks for your time taken to answer these questions and also thanks for creating this library.

Memory overload when downloading large files.

Hello,

I keep challenging your great product and found recently that when I try to download a large file (like ~150 Mb for instance on screenshot below) from the server, the debug navigator shows that it makes a huge impact to device memory. Moreover, it multiplies on number of simultaneous downloads.

Well, is it a bug or architecture pitfall? I mean is it possible to fix it?

Thanks and happy coding!

screen shot 2017-11-14 at 8 47 21 pm

Telegraph WebSocket Server kills the connection when sending a data flood

I'm using Telegraph Websocket Server component on an iOS app, which have clients connect to it and receive lots of data from the server. After not long of doing this, the connection between the sockets gets trashed and disconnects. For testing purposes I have the server configured not to use a secure connection.

The errors I get from the server are:

- Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo={NSLocalizedDescription=Socket closed by remote peer}
- Error Domain=NSPOSIXErrorDomain Code=32 "Broken pipe" UserInfo={NSLocalizedDescription=Broken pipe, NSLocalizedFailureReason=Error in write() function}

Testing with an iOS client using Starscream Websockets, I get the following error:
The operation couldn’t be completed. (Starscream.WSError error 1.)

Testing with an Adroid client using Java-WebSocket, I get the following errors:

[14:10, 12/2/2018] +972 52-455-7171: D/WebSocketClient: onError(): 
org.java_websocket.exceptions.InvalidFrameException: Unknown opcode 15
at org.java_websocket.drafts.Draft_6455.toOpcode(Draft_6455.java:519)
at org.java_websocket.drafts.Draft_6455.translateSingleFrame(Draft_6455.java:291)
at org.java_websocket.drafts.Draft_6455.translateFrame(Draft_6455.java:395)
at org.java_websocket.WebSocketImpl.decodeFrames(WebSocketImpl.java:366)
at org.java_websocket.WebSocketImpl.decode(WebSocketImpl.java:202)
at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:278)
at java.lang.Thread.run(Thread.java:818)

[14:11, 12/2/2018] +972 52-455-7171: onError(): 
org.java_websocket.exceptions.InvalidFrameException: Unknown opcode 11
at org.java_websocket.drafts.Draft_6455.toOpcode(Draft_6455.java:519)
at org.java_websocket.drafts.Draft_6455.translateSingleFrame(Draft_6455.java:291)
at org.java_websocket.drafts.Draft_6455.translateFrame(Draft_6455.java:395)
at org.java_websocket.WebSocketImpl.decodeFrames(WebSocketImpl.java:366)
at org.java_websocket.WebSocketImpl.decode(WebSocketImpl.java:202)
at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:278)
at `java.lang.Thread.run(Thread.java:818)

I'm positive the problem is related to the Websocket server, as using a Websocket server from PocketSocket pod works with these clients running the same code without disconnecting.

Swift Concurrency warnings on MacOS with XCode 9

I am seeing the following Swift runtime warnings when running a server on MacOS. This was build on MacOS 10.12 with XCode 9. Everything still seems to work fine, but these look ominous.

Simultaneous accesses to 0x6000001e0128, but modification requires exclusive access.
Previous access (a modification) started at Telegraph`closure #1 in HTTPParser.parse(data:) + 161 (0x100326e51).
Current access (a read) started at:
0    libswiftCore.dylib                 0x0000000100796930 swift_beginAccess + 605
1    Telegraph                          0x0000000100327e70 HTTPParser.parsedURI(fragment:) + 582
2    Telegraph                          0x0000000100325ab0 onParsedURL(cParser:bytes:length:) + 286
3    Telegraph                          0x0000000100325aa0 @objc onParsedURL(cParser:bytes:length:) + 9
4    HTTPParserC                        0x0000000100ff33d0 http_parser_execute + 7622
5    Telegraph                          0x0000000100326db0 closure #1 in HTTPParser.parse(data:) + 530
6    Telegraph                          0x00000001003270a0 partial apply for closure #1 in HTTPParser.parse(data:) + 102
7    Telegraph                          0x0000000100327110 thunk for @callee_owned (@unowned UnsafePointer<Int8>) -> (@unowned Int, @error @owned Error) + 26
8    Telegraph                          0x00000001003271c0 partial apply for thunk for @callee_owned (@unowned UnsafePointer<Int8>) -> (@unowned Int, @error @owned Error) + 91
9    libswiftFoundation.dylib           0x0000000100c14610 Data.withUnsafeBytes<A, B>(_:) + 253
10   Telegraph                          0x0000000100326920 HTTPParser.parse(data:) + 310
11   Telegraph                          0x0000000100330050 HTTPConnection.received(data:) + 242
12   Telegraph                          0x0000000100331650 HTTPConnection.socketDidRead(_:data:) + 79
13   Telegraph                          0x00000001003318c0 protocol witness for TCPSocketDelegate.socketDidRead(_:data:) in conformance HTTPConnection + 9
14   Telegraph                          0x0000000100323080 TCPSocket.socket(_:didRead:withTag:) + 412
15   Telegraph                          0x0000000100323250 @objc TCPSocket.socket(_:didRead:withTag:) + 97
16   CocoaAsyncSocket                   0x0000000100f9fdb0 __37-[GCDAsyncSocket completeCurrentRead]_block_invoke + 83
17   libdispatch.dylib                  0x000000010100bcf2 _dispatch_call_block_and_release + 12
18   libdispatch.dylib                  0x0000000101002784 _dispatch_client_callout + 8
19   libdispatch.dylib                  0x0000000101019872 _dispatch_queue_serial_drain + 205
20   libdispatch.dylib                  0x000000010100b60c _dispatch_queue_invoke + 1174
21   libdispatch.dylib                  0x000000010100476d _dispatch_root_queue_drain + 671
22   libdispatch.dylib                  0x00000001010046ab _dispatch_worker_thread3 + 114
23   libsystem_pthread.dylib            0x00000001010792c7 _pthread_wqthread + 1299
24   libsystem_pthread.dylib            0x00000001010792a8 start_wqthread + 13

Simultaneous accesses to 0x6000001e0128, but modification requires exclusive access.
Previous access (a modification) started at Telegraph`closure #1 in HTTPParser.parse(data:) + 161 (0x100326e51).
Current access (a read) started at:
0    libswiftCore.dylib                 0x0000000100796930 swift_beginAccess + 605
1    Telegraph                          0x0000000100329b00 HTTPParser.messageComplete() + 134
2    Telegraph                          0x0000000100326790 onMessageComplete(cParser:) + 181
3    Telegraph                          0x0000000100326780 @objc onMessageComplete(cParser:) + 9
4    HTTPParserC                        0x0000000100ff33d0 http_parser_execute + 19674
5    Telegraph                          0x0000000100326db0 closure #1 in HTTPParser.parse(data:) + 530
6    Telegraph                          0x00000001003270a0 partial apply for closure #1 in HTTPParser.parse(data:) + 102
7    Telegraph                          0x0000000100327110 thunk for @callee_owned (@unowned UnsafePointer<Int8>) -> (@unowned Int, @error @owned Error) + 26
8    Telegraph                          0x00000001003271c0 partial apply for thunk for @callee_owned (@unowned UnsafePointer<Int8>) -> (@unowned Int, @error @owned Error) + 91
9    libswiftFoundation.dylib           0x0000000100c14610 Data.withUnsafeBytes<A, B>(_:) + 253
10   Telegraph                          0x0000000100326920 HTTPParser.parse(data:) + 310
11   Telegraph                          0x0000000100330050 HTTPConnection.received(data:) + 242
12   Telegraph                          0x0000000100331650 HTTPConnection.socketDidRead(_:data:) + 79
13   Telegraph                          0x00000001003318c0 protocol witness for TCPSocketDelegate.socketDidRead(_:data:) in conformance HTTPConnection + 9
14   Telegraph                          0x0000000100323080 TCPSocket.socket(_:didRead:withTag:) + 412
15   Telegraph                          0x0000000100323250 @objc TCPSocket.socket(_:didRead:withTag:) + 97
16   CocoaAsyncSocket                   0x0000000100f9fdb0 __37-[GCDAsyncSocket completeCurrentRead]_block_invoke + 83
17   libdispatch.dylib                  0x000000010100bcf2 _dispatch_call_block_and_release + 12
18   libdispatch.dylib                  0x0000000101002784 _dispatch_client_callout + 8
19   libdispatch.dylib                  0x0000000101019872 _dispatch_queue_serial_drain + 205
20   libdispatch.dylib                  0x000000010100b60c _dispatch_queue_invoke + 1174
21   libdispatch.dylib                  0x000000010100476d _dispatch_root_queue_drain + 671
22   libdispatch.dylib                  0x00000001010046ab _dispatch_worker_thread3 + 114
23   libsystem_pthread.dylib            0x00000001010792c7 _pthread_wqthread + 1299
24   libsystem_pthread.dylib            0x00000001010792a8 start_wqthread + 13

External POST request

The demo now contains a demonstration of the server dealing with a POST with JSON data. However, hitting the server externally seems to not deal with the data correctly. Try this:

curl -X POST -H "Content-Type:application/json" -d '{"name":"Yvo"}' https://localhost:9000/data

The HTTPResponse is {"welcome":"stranger"}

Sorry - figured it out - alien characters in the curl line

Exception thrown at : HttpParser.swift->parsedURI()

Hello,

I'm trying to develop a https app by Telegraph. When I run the demo project that changed to unsecured, access http://localhost:9000/hello/abc, or http://localhost:9000.

Code throws a exception at HttpParser.swift->parsedURI() function position is in line 100: guard cParser.isURIComplete else { return continueParsing }
detail exception information is following:

Simultaneous accesses to 0x1c01e7b28, but modification requires exclusive access.
Previous access (a modification) started at Telegraph`closure #1 in HTTPParser.parse(data:) + 116 (0x1012f1e9c).
Current access (a read) started at:
0    libswiftCore.dylib                 0x00000001016d5a38 swift_beginAccess + 468
1    Telegraph                          0x00000001012f2c8c HTTPParser.parsedURI(fragment:) + 488
2    Telegraph                          0x00000001012f0d08 onParsedURL(cParser:bytes:length:) + 244
3    Telegraph                          0x00000001012f0cf4 @objc onParsedURL(cParser:bytes:length:) + 12
4    HTTPParserC                        0x00000001011b54c0 http_parser_execute + 7464
5    Telegraph                          0x00000001012f1e28 closure #1 in HTTPParser.parse(data:) + 356
6    Telegraph                          0x00000001012f20c4 thunk for @callee_owned (@unowned UnsafePointer<Int8>) -> (@unowned Int, @error @owned Error) + 36
7    Telegraph                          0x00000001012f2184 partial apply for thunk for @callee_owned (@unowned UnsafePointer<Int8>) -> (@unowned Int, @error @owned Error) + 96
8    libswiftFoundation.dylib           0x0000000101b5bf40 Data.withUnsafeBytes<A, B>(_:) + 272
9    Telegraph                          0x00000001012f1a48 HTTPParser.parse(data:) + 260
10   Telegraph                          0x00000001012de8d8 HTTPConnection.received(data:) + 188
11   Telegraph                          0x00000001012dfbc8 HTTPConnection.socketDidRead(_:data:) + 88
12   Telegraph                          0x00000001012dfe24 protocol witness for TCPSocketDelegate.socketDidRead(_:data:) in conformance HTTPConnection + 12
13   Telegraph                          0x0000000101315f80 TCPSocket.socket(_:didRead:withTag:) + 332
14   Telegraph                          0x00000001013160f8 @objc TCPSocket.socket(_:didRead:withTag:) + 144
15   CocoaAsyncSocket                   0x0000000101126410 __37-[GCDAsyncSocket completeCurrentRead]_block_invoke + 96
16   libdispatch.dylib                  0x0000000101ecd484 _dispatch_call_block_and_release + 24
17   libdispatch.dylib                  0x0000000101ecd44c _dispatch_client_callout + 16
18   libdispatch.dylib                  0x0000000101edbe5c _dispatch_queue_serial_drain + 692
19   libdispatch.dylib                  0x0000000101ed0858 _dispatch_queue_invoke + 332
20   libdispatch.dylib                  0x0000000101edcf5c _dispatch_root_queue_drain_deferred_wlh + 424
21   libdispatch.dylib                  0x0000000101ee3e74 _dispatch_workloop_worker_thread + 652
22   libsystem_pthread.dylib            0x000000018388ac3c _pthread_wqthread + 932
23   libsystem_pthread.dylib            0x000000018388ac2c start_wqthread + 4

My device is iPhone 5s, iOS version is 11, Deployment target version have be tried from 9.0 to 11.0.

Do you know what's the reason, Thank you very much

Access control allow origin

Hi Zyphrax,

I'm writing a REST service in my app to serve an image when called. Let say my iPad web server is listening on 192.168.1.97:9000, configured as unsecure server.

Calling client is an angularjs app running on my PC, let say on localhost:8080/myclientapp.
My angularjs app call http://192.168.1.97:9000/getimage but iOS app web server returns:
Failed to load http://192.168.1.97:9000/getimage/20171107121552614: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

How can I allow cross origin ajax calls on iOS unsecure web server?

EDIT: If I open this URL http://192.168.1.97:9000/getimage/20171107121552614 from a Chrome tab it correctly returns b64 image data without complain.

Thank you.

can not set Sec-WebSocket-Protocol

Telegraph has defined header Sec-WebSocket-Protocol, but it is hard coded in HTTPMessage+WebSocket.swift (line 38). Outside, we can not set the header, it will be overridden. But Sec-WebSocket-Protocol is very important. Most of time we need to set it.

WebSocket disconnected, error: The handshake request failed with status 101 Web Socket Protocol Handshake

extension HTTPStatus {
  public static func == (lhs: HTTPStatus, rhs: HTTPStatus) -> Bool {
    return lhs.code == rhs.code && lhs.phrase == rhs.phrase
  }
}

static let switchingProtocols = HTTPStatus(code: 101, phrase: "Switching Protocols")

But some other Websocket Server (like Java-WebSocket) returned
code:101, phrase:"Web Socket Protocol Handshake"

So the Telegraph client can not connect to this server.
The handshake request failed with status 101 Web Socket Protocol Handshake

Error with start

Showing Recent Messages
👎 Cycle inside iOS Example; building could produce unreliable results. This usually can be resolved by moving the shell script phase 'h' so that it runs before the build phase that depends on its outputs.
Cycle details:
→ That command depends on command in Target 'iOS Example': script phase “[CP] Embed Pods Frameworks”
○ That command depends on command in Target 'iOS Example': script phase “[CP] Embed Pods Frameworks”

How to use html file like nginx?

I want to use it to make an html server,but I didn't find any information about that.Do you have any good advice or guidance to help me? Thank you very much.

Serving mp4 video

I am trying to serve a video in mp4 format without any luck. The player shows with a line/slash above the play symbol. Do this server support HTTP range requests= Will this be possible without setting up sockets or other configuration? I will appreciate any help. Here are some code snippets from my project:

override func viewDidLoad() {
    let web = WKWebView(frame: CGRect(x: 0, y: 0, width:self.view.frame.width, height:
        self.view.frame.height), configuration: webConfiguration)
    let request = URLRequest(url: customServerURL(path: "/samplemodule/chrome-clip.mp4"))
    web.load(request as URLRequest)
    self.view.addSubview(web)
    self.view.bringSubview(toFront: web)
}
func startWebServer(){
    if let identity = identity, let caCertificate = caCertificate {
        server = Server(identity: identity, caCertificates: [caCertificate])
    } else {
        server = Server()
    }
    
    server.webSocketConfig.pingInterval = 10
    server.webSocketDelegate = self
    
    try! server.start(onPort: 9000)
    server.route(.post, "data", serverHandleData)

    server.route(.get, "hello/:name", serverHandleHello)
    server.route(.get, "hello(/)", serverHandleHello)
    
    server.route(.get, "secret/*") { .forbidden }
    server.route(.get, "status") { (.ok, "Server is running") }
    server.serveBundle(.main, "/")
    
    let demoBundleURL = Bundle.main.url(forResource: "samplemodule", withExtension: nil)!
    server.serveDirectory(demoBundleURL, "/samplemodule")
}

How to use CORS?

I want to call "localhost" from another domain.
How to setting CORS?

Matching routes question.

Hello,

Just found that HTTPRouteHandler matches any route that can handle our path. For instance, I add only .get and .delete routes with the same path with parameter, but server also response on .put and .post methods on that path (testing by Rested app as a client).

Is it a bug or feature? Or I just need to check method in the request's handler?

Thanks, and happy coding!

WebSocket will close connection for large payload

Hello 👋

Not sure if this is maybe somehow related to #30

I have an issue when trying to send large payload using WebSocket.
The data that is being sent is encoded using JSONEncoder() and simply sent using self?.webSocket.send(data: data). For small amount of data (around 300KB) it works fine, but for large payloads (around 1MB) it will close the socket. In Charles proxy I can see that there is an error: (1002) WebSocket Protocol Error .

The data is being sent for websocket in webSocketDelegate function self.serverHTTP.webSocketDelegate = self

func server(_ server: Server, webSocketDidConnect webSocket: WebSocket, handshake: HTTPRequest)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.