EV-Nats

 view release on metacpan or  search on metacpan

src/EV__Nats.xs  view on Meta::CPAN

            char *e = line + len;
            char *found;

            /* max_payload accumulates into a signed int: parse wide and
               clamp to INT_MAX so a hostile INFO cannot poison it negative */
            found = (char *)nats_memfind(p, (size_t)(e - p), "\"max_payload\":", 14);
            if (found) {
                found += 14;
                uint64_t mp = 0;
                char *digits = found;
                while (found < e && *found >= '0' && *found <= '9') {
                    uint64_t d = (uint64_t)(*found - '0');
                    if (mp <= (UINT64_MAX - d) / 10)
                        mp = mp * 10 + d;
                    else
                        mp = UINT64_MAX;
                    found++;
                }
                if (found > digits && mp > 0)
                    self->max_payload = mp > (uint64_t)INT_MAX ? INT_MAX : (int)mp;
            }

            nats_parse_connect_urls(self, p, e - p);

            /* Parse nonce for NKey auth */
            found = (char *)nats_memfind(p, (size_t)(e - p), "\"nonce\":\"", 9);
            if (found) {
                found += 9;
                const char *nend = memchr(found, '"', e - found);
                if (nend) {
                    size_t nlen = nend - found;
                    if (self->server_nonce) Safefree(self->server_nonce);
                    Newx(self->server_nonce, nlen + 1, char);
                    memcpy(self->server_nonce, found, nlen);
                    self->server_nonce[nlen] = '\0';
                }
            }

            /* Parse ldm (lame duck mode) */
            found = (char *)nats_memfind(p, (size_t)(e - p), "\"ldm\":", 6);
            if (found) {
                found += 6;
                while (found < e && (*found == ' ' || *found == '\t')) found++;
                if (found < e && *found == 't') {
                    if (!self->ldm) {
                        self->ldm = 1;
                        if (self->on_ldm) {
                            dSP;
                            ENTER; SAVETMPS;
                            PUSHMARK(SP);
                            PUTBACK;
                            PINNED_CALL_SV(self->on_ldm, G_DISCARD);
                            FREETMPS; LEAVE;
                        }
                    }
                }
            }
        }

        if (self->connecting) {
            /* tls_required: CONNECT would leak credentials over plaintext
               before the server could reject it; refuse instead */
            {
                const char *tr = nats_memfind(line + 5, len - 5, "\"tls_required\":", 15);
                if (tr) {
                    const char *tre = line + len;
                    int tls_active = 0;
                    tr += 15;
                    while (tr < tre && (*tr == ' ' || *tr == '\t')) tr++;
#ifdef HAVE_OPENSSL
                    tls_active = self->tls;
#endif
                    if ((size_t)(tre - tr) >= 4 && memcmp(tr, "true", 4) == 0 && !tls_active) {
                        self->intentional_disconnect = 1;
                        nats_emit_error(self, "server requires TLS but TLS is not enabled");
                        nats_cleanup(self);
                        return;
                    }
                }
            }
#ifdef HAVE_OPENSSL
            if (self->tls && !self->ssl) {
                if (nats_ssl_setup(self) != 0) {
                    nats_ssl_fail(self, "SSL setup failed");
                    return;
                }
                self->ssl_handshaking = 1;
                int hret = nats_ssl_handshake(self);
                if (hret < 0) {
                    nats_ssl_fail(self, "SSL handshake failed");
                    return;
                }
                if (hret == 1) {
                    self->ssl_handshaking = 0;
                    nats_send_connect(self);
                    nats_try_write(self);
                }
                /* hret == 0: handshake in progress; nats_on_read will resume. */
                return;
            }
#endif
            nats_send_connect(self);
            nats_try_write(self);
        }
        return;
    }

    /* MSG */
    if (len >= 4 && line[0] == 'M' && line[1] == 'S' && line[2] == 'G' && line[3] == ' ') {
        if (nats_parse_msg_args(self, line, len) == 0) {
            /* max_payload is a signed int a hostile INFO could poison;
               the +2 check rejects lengths whose trailing CRLF would wrap */
            size_t limit = self->max_payload > 0 ? (size_t)self->max_payload
                                                 : (size_t)DEFAULT_MAX_PAYLOAD;
            if (self->msg_total_len > limit || self->msg_total_len > SIZE_MAX - 2) {
                nats_emit_error(self, "server sent message exceeding max_payload");
                nats_cleanup(self);
                return;
            }
            self->parse_state = PARSE_MSG_BODY;
        }



( run in 1.927 second using v1.01-cache-2.11-cpan-f0ff5d10edf )