danielrhodes / Swift-ActionCableClient

ActionCable is a new WebSocket server being released with Rails 5 which makes it easy to add real-time features to your app. This Swift client makes it dead-simple to connect with that server, abstracting away everything except what you need to get going.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Headers not being assigned

NicosKaralis opened this issue · comments

After some debugging I've found that the headers setter is calling the getter which calls a dynamic getter and ignores the new values

This declaration

    open var headers : [String: String]? {
        get { return socket.request.allHTTPHeaderFields }
        set {
            for (field, value) in headers ?? [:] {
                socket.request.setValue(value, forHTTPHeaderField: field)
            }
        }
    }

Should be replaced with this

    open var headers : [String: String]? {
        get { return socket.request.allHTTPHeaderFields }
        set {
            for (field, value) in newValue ?? [:] {
                socket.request.setValue(value, forHTTPHeaderField: field)
            }
        }
    }

If you need a test just run this example

  let client: ActionCableClient = {
    let _client = ActionCableClient(url: Defaults.Api.cableURL)
    _client.headers = [
      "Origin": "https://server.example"
    ]
    return _client
  }()
  print(client.headers)
  client.headers = [
    "Origin": "https://server.example",
    "Accept": "accept/json"
  ]
  print(client.headers)
  if !client.isConnected {
    client.connect()
  }

https://github.com/danielrhodes/Swift-ActionCableClient/blob/master/Source/Classes/ActionCableClient.swift#L77

After more headscreatching I've found another problem with variable names.

My server handles authentication via the Authorization header and it rejects the connection if the token is not right. But for some reason the client never got the message and kept retrying

This was the offending code on Error.swift:

    init(from error: Swift.Error) {
      switch error._code {

._code is a private variable and should not be used to identify the error. Since the error received is a WSError a more sane approach would be.

    init(from error: Swift.Error) {
      let error_code: Int
      if let ws_error = error as? WSError {
        error_code = ws_error.code
      } else {
        error_code = error._code
      }
      
      switch error_code {

We look for an WSError if it is not the correct class then we use a fallback

I'll update the pull request to include this fix