EV-Websockets

 view release on metacpan or  search on metacpan

Websockets.xs  view on Meta::CPAN

    int closing;
};

#define EV_WS_PROTOCOL_NAME "ev-websockets"

/* Extensions support (compression) */
#ifdef LWS_HAS_EXTENSIONS
static const struct lws_extension extensions[] = {
    {
        "permessage-deflate",
        lws_extension_callback_pm_deflate,
        "permessage-deflate; client_no_context_takeover; client_max_window_bits"
    },
    { NULL, NULL, NULL }
};
#endif

static int ev_ws_debug = 0;

/* Bridges userdata into ws_callback() before lws_adopt returns. */
static ev_ws_conn_t* pending_adoption = NULL;
static HV* handshake_headers_map = NULL; /* wsi-ptr → per-conn response headers HV */
static struct lws_context* ssl_keepalive_ctx = NULL; /* see ensure_ssl_keepalive() */

/* Copy an lws header token into a fresh SV, or return NULL if absent/empty */
static SV* hdr_to_sv(struct lws *wsi, enum lws_token_indexes tok) {
    int total = lws_hdr_total_length(wsi, tok);
    if (total > 0) {
        char *buf;
        int n;
        Newx(buf, total + 1, char);
        n = lws_hdr_copy(wsi, buf, total + 1, tok);
        if (n > 0) {
            SV *val = newSVpvn(buf, n);
            Safefree(buf);
            return val;
        }
        Safefree(buf);
    }
    return NULL;
}

/* Capture a header value into an HV under the given key */
static void capture_header(struct lws *wsi, HV *hv, enum lws_token_indexes tok,
                           const char *name, STRLEN nlen) {
    SV *val = hdr_to_sv(wsi, tok);
    if (val && !hv_store(hv, name, nlen, val, 0))
        SvREFCNT_dec(val);
}

typedef struct { enum lws_token_indexes tok; const char *name; STRLEN nlen; } header_def_t;

static const header_def_t request_hdrs[] = {
    { WSI_TOKEN_GET_URI, "Path", 4 },
    { WSI_TOKEN_HOST, "Host", 4 },
    { WSI_TOKEN_ORIGIN, "Origin", 6 },
    { WSI_TOKEN_HTTP_COOKIE, "Cookie", 6 },
    { WSI_TOKEN_HTTP_AUTHORIZATION, "Authorization", 13 },
    { WSI_TOKEN_PROTOCOL, "Sec-WebSocket-Protocol", 22 },
    { WSI_TOKEN_HTTP_USER_AGENT, "User-Agent", 10 },
    { WSI_TOKEN_X_FORWARDED_FOR, "X-Forwarded-For", 15 },
};
#define N_REQUEST_HDRS (int)(sizeof(request_hdrs)/sizeof(request_hdrs[0]))

static void capture_request_headers(struct lws *wsi, HV *hv) {
    int i;
    for (i = 0; i < N_REQUEST_HDRS; i++)
        capture_header(wsi, hv, request_hdrs[i].tok,
                       request_hdrs[i].name, request_hdrs[i].nlen);
}

/* Inject all key/value pairs from an HV as HTTP headers via lws.
   Returns -1 if lws rejected a header (client path aborts the handshake);
   server callers ignore the result and simply stop adding. */
static int inject_headers(struct lws *wsi, HV *hv,
                          unsigned char **p, unsigned char *end) {
    HE *entry;
    char kbuf[256];
    hv_iterinit(hv);
    while ((entry = hv_iternext(hv))) {
        I32 klen;
        const char *key = hv_iterkey(entry, &klen);
        SV *val_sv;
        STRLEN vlen;
        const char *val;
        if (klen >= 254) continue;
        val_sv = hv_iterval(hv, entry);
        val = SvPV(val_sv, vlen);
        memcpy(kbuf, key, klen);
        kbuf[klen] = ':';
        kbuf[klen + 1] = '\0';
        if (lws_add_http_header_by_name(wsi, (unsigned char *)kbuf,
                (unsigned char *)val, vlen, p, end))
            return -1;
    }
    return 0;
}

/* Format a wsi pointer as the lookup key for handshake_headers_map.
   Callers must pass a buffer of at least 32 bytes; returns the key length. */
static int wsi_key(char *buf, struct lws *wsi) {
    return snprintf(buf, 32, "%p", (void*)wsi);
}

#define DEBUG_LOG(fmt, ...) do { if (ev_ws_debug) fprintf(stderr, "[EV::WS] " fmt "\n", ##__VA_ARGS__); } while(0)

static void ctx_ref(ev_ws_ctx_t* ctx) {
    ctx->refcnt++;
}

static void ctx_unref(ev_ws_ctx_t* ctx) {
    if (--ctx->refcnt == 0) {
        Safefree(ctx);
    }
}

/* Schedule the next lws housekeeping wake-up.

   lws_service_adjust_timeout returns the ms until lws next needs servicing; 0
   means "service as soon as possible". This timer only paces lws's time-based
   work (connection/handshake timeouts, TLS cert aging, draining buffered rx) --



( run in 0.677 second using v1.01-cache-2.11-cpan-13bb782fe5a )