static int websocket_handshake(swListenPort *port, http_context *ctx) { #if PHP_MAJOR_VERSION < 7 TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); #endif zval *header = ctx->request.zheader; HashTable *ht = Z_ARRVAL_P(header); zval *pData; if (sw_zend_hash_find(ht, ZEND_STRS("sec-websocket-key"), (void **) &pData) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "header no sec-websocket-key"); return SW_ERR; } convert_to_string(pData); swString_clear(swoole_http_buffer); swString_append_ptr(swoole_http_buffer, ZEND_STRL("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\n")); int n; char sec_websocket_accept[128]; memcpy(sec_websocket_accept, Z_STRVAL_P(pData), Z_STRLEN_P(pData)); memcpy(sec_websocket_accept + Z_STRLEN_P(pData), SW_WEBSOCKET_GUID, sizeof(SW_WEBSOCKET_GUID) - 1); char sha1_str[20]; bzero(sha1_str, sizeof(sha1_str)); php_swoole_sha1(sec_websocket_accept, Z_STRLEN_P(pData) + sizeof(SW_WEBSOCKET_GUID) - 1, (unsigned char *) sha1_str); char encoded_str[50]; bzero(encoded_str, sizeof(encoded_str)); n = swBase64_encode((unsigned char *) sha1_str, sizeof(sha1_str), encoded_str); char _buf[128]; n = snprintf(_buf, sizeof(_buf), "Sec-WebSocket-Accept: %*s\r\n", n, encoded_str); swString_append_ptr(swoole_http_buffer, _buf, n); swString_append_ptr(swoole_http_buffer, ZEND_STRL("Sec-WebSocket-Version: "SW_WEBSOCKET_VERSION"\r\n")); if (port->websocket_subprotocol) { swString_append_ptr(swoole_http_buffer, ZEND_STRL("Sec-WebSocket-Protocol: ")); swString_append_ptr(swoole_http_buffer, port->websocket_subprotocol, port->websocket_subprotocol_length); swString_append_ptr(swoole_http_buffer, ZEND_STRL("\r\n")); } swString_append_ptr(swoole_http_buffer, ZEND_STRL("Server: "SW_WEBSOCKET_SERVER_SOFTWARE"\r\n\r\n")); swTrace("websocket header len:%ld\n%s \n", swoole_http_buffer->length, swoole_http_buffer->str); return swServer_tcp_send(SwooleG.serv, ctx->fd, swoole_http_buffer->str, swoole_http_buffer->length); }
/** * default onRequest callback */ void swoole_websocket_onReuqest(swoole_http_client *client) { char *content = "<html><body><h2>HTTP ERROR 400</h2><hr><i>Powered by "SW_HTTP_SERVER_SOFTWARE" ("PHP_SWOOLE_VERSION")</i></body></html>"; char *bad_request = "HTTP/1.1 400 Bad Request\r\n"\ "Content-Type: text/html; charset=UTF-8\r\n"\ "Cache-Control: must-revalidate,no-cache,no-store\r\n"\ "Content-Length: %d\r\n"\ "Server: "SW_HTTP_SERVER_SOFTWARE"\r\n\r\n%s"; char buf[512]; int n = sprintf(buf, bad_request, strlen(content), content); swServer_tcp_send(SwooleG.serv, client->fd, buf, n); SwooleG.serv->factory.end(&SwooleG.serv->factory, client->fd); }
static int websocket_handshake(http_client *client) { //HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: %s\r\nSec-WebSocket-Version: %s\r\nKeepAlive: off\r\nContent-Length: 0\r\nServer: ZWebSocket\r\n TSRMLS_FETCH_FROM_CTX(sw_thread_ctx ? sw_thread_ctx : NULL); zval *header = zend_read_property(swoole_http_request_class_entry_ptr, client->zrequest, ZEND_STRL("header"), 1 TSRMLS_CC); HashTable *ht = Z_ARRVAL_P(header); zval **pData; if(zend_hash_find(ht, ZEND_STRS("sec-websocket-key") , (void **) &pData) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "header no sec-websocket-key"); return SW_ERR; } convert_to_string(*pData); // swTrace("key: %s len:%d\n", Z_STRVAL_PP(pData), Z_STRLEN_PP(pData)); swString *buf = swString_new(256); swString_append_ptr(buf, ZEND_STRL("HTTP/1.1 101 Switching Protocols\r\n")); swString_append_ptr(buf, ZEND_STRL("Upgrade: websocket\r\nConnection: Upgrade\r\n")); swString *shaBuf = swString_new(Z_STRLEN_PP(pData)+36); swString_append_ptr(shaBuf, Z_STRVAL_PP(pData), Z_STRLEN_PP(pData)); swString_append_ptr(shaBuf, ZEND_STRL(SW_WEBSOCKET_GUID)); char data_str[20]; // bzero(data_str, sizeof(data_str)); // swTrace("sha1 start:%s\n", shaBuf->str); sha1(shaBuf->str, (unsigned char *) data_str); char encoded_value[50]; bzero(encoded_value, sizeof(encoded_value)); // swTrace("base64_encode start:%d\n", sizeof(data_str)); swBase64_encode((unsigned char *) data_str, 20, encoded_value); // swTrace("base64_encode end:%s %d %d\n", encoded_value, encoded_len, strlen(encoded_value)); char _buf[128]; int n = 0; n = snprintf(_buf, strlen(encoded_value)+25, "Sec-WebSocket-Accept: %s\r\n", encoded_value); // efree(data_str); // efree(encoded_value); swString_free(shaBuf); // swTrace("accept value: %s\n", _buf); swString_append_ptr(buf, _buf, n); swString_append_ptr(buf, ZEND_STRL("Sec-WebSocket-Version: 13\r\n")); swString_append_ptr(buf, ZEND_STRL("Server: swoole-websocket\r\n\r\n")); swTrace("websocket header len:%zd\n%s \n", buf->length, buf->str); int ret = swServer_tcp_send(SwooleG.serv, client->fd, buf->str, buf->length); swString_free(buf); // swTrace("handshake send: %d lenght: %d\n", client->fd, ret); return ret; }
static PHP_METHOD(swoole_websocket_server, push) { zval *zdata; long fd = 0; long opcode = WEBSOCKET_OPCODE_TEXT_FRAME; zend_bool fin = 1; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|lb", &fd, &zdata, &opcode, &fin) == FAILURE) { return; } if (fd <= 0) { swoole_php_fatal_error(E_WARNING, "fd[%d] is invalid.", (int )fd); RETURN_FALSE; } if (opcode > WEBSOCKET_OPCODE_PONG) { swoole_php_fatal_error(E_WARNING, "opcode max 10"); RETURN_FALSE; } char *data; int length = php_swoole_get_send_data(zdata, &data TSRMLS_CC); if (length < 0) { RETURN_FALSE; } else if (length == 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "data is empty."); RETURN_FALSE; } swConnection *conn = swWorker_get_connection(SwooleG.serv, fd); if (!conn || conn->websocket_status < WEBSOCKET_STATUS_HANDSHAKE) { swoole_php_fatal_error(E_WARNING, "connection[%d] is not a websocket client.", (int ) fd); RETURN_FALSE; } swString_clear(swoole_http_buffer); swWebSocket_encode(swoole_http_buffer, data, length, opcode, (int) fin, 0); SW_CHECK_RETURN(swServer_tcp_send(SwooleG.serv, fd, swoole_http_buffer->str, swoole_http_buffer->length)); }
/** * default onRequest callback */ void swoole_websocket_onRequest(http_context *ctx) { SWOOLE_GET_TSRMLS; char *content = "<html><body><h2>HTTP ERROR 400</h2><hr><i>Powered by "SW_HTTP_SERVER_SOFTWARE" ("PHP_SWOOLE_VERSION")</i></body></html>"; char *bad_request = "HTTP/1.1 400 Bad Request\r\n"\ "Content-Type: text/html; charset=UTF-8\r\n"\ "Cache-Control: must-revalidate,no-cache,no-store\r\n"\ "Content-Length: %d\r\n"\ "Server: "SW_HTTP_SERVER_SOFTWARE"\r\n\r\n%s"; char buf[512]; int n = sprintf(buf, bad_request, strlen(content), content); swServer_tcp_send(SwooleG.serv, ctx->fd, buf, n); ctx->end = 1; swServer_tcp_close(SwooleG.serv, ctx->fd, 0); swoole_http_context_free(ctx TSRMLS_CC); }