/** * @zobject: swoole_client object */ static int php_swoole_client_close(zval **zobject, int fd TSRMLS_DC) { zval *zcallback = NULL; zval *retval; zval **args[1]; swClient *cli; char *hash_key; int hash_key_len; hash_key_len = spprintf(&hash_key, sizeof(int)+1, "%d", fd); if (zend_hash_find(&php_sw_client_callback, hash_key, hash_key_len+1, (void **)&zobject) != SUCCESS) { zend_error(E_WARNING, "swoole_client->close: Fd[%d] is not a swoole_client object", fd); efree(hash_key); return SW_ERR; } zcallback = zend_read_property(swoole_client_class_entry_ptr, *zobject, SW_STRL("close")-1, 0 TSRMLS_CC); if (zcallback == NULL) { zend_error(E_WARNING, "swoole_client: swoole_client object have not close callback."); efree(hash_key); return SW_ERR; } SwooleG.main_reactor->del(SwooleG.main_reactor, fd); zval **zres; if (zend_hash_find(Z_OBJPROP_PP(zobject), SW_STRL("_client"), (void **) &zres) == SUCCESS) { ZEND_FETCH_RESOURCE_NO_RETURN(cli, swClient*, zres, -1, SW_RES_CLIENT_NAME, le_swoole_client); cli->close(cli); }
void swoole_client_init(int module_number TSRMLS_DC) { INIT_CLASS_ENTRY(swoole_client_ce, "swoole_client", swoole_client_methods); swoole_client_class_entry_ptr = zend_register_internal_class(&swoole_client_ce TSRMLS_CC); zend_declare_property_long(swoole_client_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_client_class_entry_ptr, SW_STRL("sock")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_hash_init(&php_sw_long_connections, 16, NULL, ZVAL_PTR_DTOR, 1); }
void swoole_table_init(int module_number TSRMLS_DC) { INIT_CLASS_ENTRY(swoole_table_ce, "swoole_table", swoole_table_methods); swoole_table_class_entry_ptr = zend_register_internal_class(&swoole_table_ce TSRMLS_CC); #ifdef HAVE_PCRE zend_class_implements(swoole_table_class_entry_ptr TSRMLS_CC, 2, spl_ce_Iterator, spl_ce_Countable); #endif zend_declare_class_constant_long(swoole_table_class_entry_ptr, SW_STRL("TYPE_INT")-1, SW_TABLE_INT TSRMLS_CC); zend_declare_class_constant_long(swoole_table_class_entry_ptr, SW_STRL("TYPE_STRING")-1, SW_TABLE_STRING TSRMLS_CC); zend_declare_class_constant_long(swoole_table_class_entry_ptr, SW_STRL("TYPE_FLOAT")-1, SW_TABLE_FLOAT TSRMLS_CC); }
void swoole_client_init(int module_number TSRMLS_DC) { INIT_CLASS_ENTRY(swoole_client_ce, "swoole_client", swoole_client_methods); swoole_client_class_entry_ptr = zend_register_internal_class(&swoole_client_ce TSRMLS_CC); zend_declare_property_long(swoole_client_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_client_class_entry_ptr, SW_STRL("sock")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); php_sw_long_connections = swHashMap_new(SW_HASHMAP_INIT_BUCKET_N, NULL); zend_declare_class_constant_long(swoole_client_class_entry_ptr, ZEND_STRL("MSG_OOB"), MSG_OOB TSRMLS_CC); zend_declare_class_constant_long(swoole_client_class_entry_ptr, ZEND_STRL("MSG_PEEK"), MSG_PEEK TSRMLS_CC); zend_declare_class_constant_long(swoole_client_class_entry_ptr, ZEND_STRL("MSG_DONTWAIT"), MSG_DONTWAIT TSRMLS_CC); zend_declare_class_constant_long(swoole_client_class_entry_ptr, ZEND_STRL("MSG_WAITALL"), MSG_WAITALL TSRMLS_CC); }
int swHttpRequest_have_content_length(swHttpRequest *request) { swString *buffer = request->buffer; char *buf = buffer->str + buffer->offset; int len = buffer->length - buffer->offset; char *pe = buf + len; char *p; for (p = buf; p < pe; p++) { if (*p == '\r' && *(p + 1) == '\n') { if (strncasecmp(p + 2, SW_STRL("Content-Length") - 1) == 0) { return SW_TRUE; } else { p++; } } } return SW_FALSE; }
TEST(client, tcp) { int ret; swClient cli, cli2; char buf[128]; ret = swClient_create(&cli, SW_SOCK_TCP, SW_SOCK_SYNC); ASSERT_EQ(ret, 0); ret = cli.connect(&cli, (char *) "127.0.0.1", 80, 0.5, 0); ASSERT_EQ(ret, 0); ret = cli.send(&cli, (char *) SW_STRL("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"), 0); ASSERT_GT(ret, 0); ret = cli.recv(&cli, buf, 128, 0); ASSERT_GT(ret, 0); cli.close(&cli); ASSERT_EQ(strncmp(buf, SW_STRL("HTTP/1.1 200 OK\r\n") -1), 0); }
int main(int argc, char **argv) { int ret; swServer serv; swServer_init(&serv); //初始化 //config serv.backlog = 128; serv.reactor_num = 2; //reactor线程数量 serv.writer_num = 2; //writer线程数量 serv.worker_num = 2; //worker进程数量 serv.factory_mode = SW_MODE_SINGLE; //SW_MODE_PROCESS/SW_MODE_THREAD/SW_MODE_BASE/SW_MODE_SINGLE serv.max_conn = 1000; //serv.open_cpu_affinity = 1; //serv.open_tcp_nodelay = 1; //serv.daemonize = 1; serv.open_eof_check = 0; memcpy(serv.data_eof, SW_STRL("\r\n\r\n")-1); //开启eof检测,启用buffer区 // memcpy(serv.log_file, SW_STRL("/tmp/swoole.log")); //日志 serv.dispatch_mode = 2; // serv.open_tcp_keepalive = 1; serv.onStart = my_onStart; serv.onShutdown = my_onShutdown; serv.onConnect = my_onConnect; serv.onReceive = my_onReceive; serv.onClose = my_onClose; serv.onTimer = my_onTimer; serv.onWorkerStart = my_onWorkerStart; serv.onWorkerStop = my_onWorkerStop; //create Server ret = swServer_create(&serv); if (ret < 0) { swTrace("create server fail[error=%d].\n", ret); exit(0); } // swServer_addListen(&serv, SW_SOCK_UDP, "0.0.0.0", 9500); swServer_addListen(&serv, SW_SOCK_TCP, "127.0.0.1", 9501); //swServer_addListen(&serv, SW_SOCK_UDP, "127.0.0.1", 9502); //swServer_addListen(&serv, SW_SOCK_UDP, "127.0.0.1", 8888); //swServer_addTimer(&serv, 2); //swServer_addTimer(&serv, 4); // g_controller_id = serv.factory.controller(&serv.factory, my_onControlEvent); ret = swServer_start(&serv); if (ret < 0) { swTrace("start server fail[error=%d].\n", ret); exit(0); } return 0; }
/** * POST content-length */ int swHttpRequest_get_content_length(swHttpRequest *request) { swString *buffer = request->buffer; char *buf = buffer->str + buffer->offset; int len = buffer->length - buffer->offset; char *pe = buf + len; char *p; char state = 0; for (p = buf; p < pe; p++) { if (*p == '\r' && *(p + 1) == '\n') { if (state == 0) { if (strncasecmp(p + 2, SW_STRL("Content-Length") - 1) == 0) { p += sizeof("Content-Length: "); request->content_length = atoi(p); state = 1; } else { p++; } } else { if (memcmp(p + 2, SW_STRL("\r\n") - 1) == 0) { //strlen(header) + sizeof("\r\n\r\n") request->header_length = p - buffer->str + sizeof("\r\n\r\n") - 1; buffer->offset = request->header_length; return SW_OK; } } } } return SW_ERR; }
/** * @zobject: swoole_client object */ static int php_swoole_client_close(zval **zobject, int fd TSRMLS_DC) { zval *zcallback = NULL; zval *retval; zval **args[1]; swClient *cli; zval **zres; if (zend_hash_find(Z_OBJPROP_PP(zobject), SW_STRL("_client"), (void **) &zres) == SUCCESS) { ZEND_FETCH_RESOURCE_NO_RETURN(cli, swClient*, zres, -1, SW_RES_CLIENT_NAME, le_swoole_client); }
void swoole_redis_init(int module_number TSRMLS_DC) { SWOOLE_INIT_CLASS_ENTRY(swoole_redis_ce, "swoole_redis", "Swoole\\Redis", swoole_redis_methods); swoole_redis_class_entry_ptr = zend_register_internal_class(&swoole_redis_ce TSRMLS_CC); SWOOLE_CLASS_ALIAS(swoole_redis, "Swoole\\Redis"); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("onConnect"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("onClose"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("onMessage"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("setting"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("host"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("port"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("sock"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("errCode"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_redis_class_entry_ptr, ZEND_STRL("errMsg"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_class_constant_long(swoole_redis_class_entry_ptr, SW_STRL("STATE_CONNECT")-1, SWOOLE_REDIS_STATE_CONNECT TSRMLS_CC); zend_declare_class_constant_long(swoole_redis_class_entry_ptr, SW_STRL("STATE_READY")-1, SWOOLE_REDIS_STATE_READY TSRMLS_CC); zend_declare_class_constant_long(swoole_redis_class_entry_ptr, SW_STRL("STATE_WAIT_RESULT")-1, SWOOLE_REDIS_STATE_WAIT_RESULT TSRMLS_CC); zend_declare_class_constant_long(swoole_redis_class_entry_ptr, SW_STRL("STATE_SUBSCRIBE")-1, SWOOLE_REDIS_STATE_SUBSCRIBE TSRMLS_CC); zend_declare_class_constant_long(swoole_redis_class_entry_ptr, SW_STRL("STATE_CLOSED")-1, SWOOLE_REDIS_STATE_CLOSED TSRMLS_CC); }
int swHttpRequest_has_expect_header(swHttpRequest *request) { swString *buffer = request->buffer; //char *buf = buffer->str + buffer->offset; char *buf = buffer->str; //int len = buffer->length - buffer->offset; int len = buffer->length; char *pe = buf + len; char *p; for (p = buf; p < pe; p++) { if (*p == '\r' && pe - p > sizeof("\r\nExpect")) { if (strncasecmp(p + 2, SW_STRL("\r\nExpect") - 1) == 0) { p += sizeof("Expect: ") + 1; if (strncasecmp(p, SW_STRL("100-continue") - 1) == 0) { return 1; } else { return 0; } } else { p++; } } } return 0; }
void swoole_http_client_coro_init(int module_number TSRMLS_DC) { SWOOLE_INIT_CLASS_ENTRY(swoole_http_client_coro_ce, "swoole_http_client_coro", "Swoole\\Coroutine\\Http\\Client", swoole_http_client_coro_methods); swoole_http_client_coro_class_entry_ptr = zend_register_internal_class(&swoole_http_client_coro_ce TSRMLS_CC); //todo search SWOOLE_CLASS_ALIAS(swoole_http_client_coro, "Swoole\\Coroutine\\Http\\Client"); zend_declare_property_long(swoole_http_client_coro_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http_client_coro_class_entry_ptr, SW_STRL("sock")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); http_client_buffer = swString_new(SW_HTTP_RESPONSE_INIT_SIZE); if (!http_client_buffer) { swoole_php_fatal_error(E_ERROR, "[1] swString_new(%d) failed.", SW_HTTP_RESPONSE_INIT_SIZE); } #ifdef SW_HAVE_ZLIB swoole_zlib_buffer = swString_new(2048); if (!swoole_zlib_buffer) { swoole_php_fatal_error(E_ERROR, "[2] swString_new(%d) failed.", SW_HTTP_RESPONSE_INIT_SIZE); } #endif }
/** * POST content-length */ int swHttpRequest_get_content_length(swHttpRequest *request) { swString *buffer = request->buffer; char *buf = buffer->str + buffer->offset; int len = buffer->length - buffer->offset; char *pe = buf + len; char *p; char *eol; for (p = buf; p < pe; p++) { if (*p == '\r' && pe - p > sizeof("Content-Length")) { if (strncasecmp(p, SW_STRL("\r\nContent-Length") - 1) == 0) { //strlen("\r\n") + strlen("Content-Length") p += (2 + (sizeof("Content-Length:") - 1)); //skip space if (*p == ' ') { p++; } eol = strstr(p, "\r\n"); if (eol == NULL) { return SW_ERR; } request->content_length = atoi(p); return SW_OK; } } } return SW_ERR; }
void swoole_http2_client_init(int module_number TSRMLS_DC) { SWOOLE_INIT_CLASS_ENTRY(swoole_http2_client_ce, "swoole_http2_client", "Swoole\\Http2\\Client", swoole_http2_client_methods); swoole_http2_client_class_entry_ptr = sw_zend_register_internal_class_ex(&swoole_http2_client_ce, swoole_client_class_entry_ptr, "swoole_client" TSRMLS_CC); SWOOLE_CLASS_ALIAS(swoole_http2_client, "Swoole\\Http2\\Client"); zend_declare_property_null(swoole_http2_client_class_entry_ptr, SW_STRL("requestHeaders")-1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_client_class_entry_ptr, SW_STRL("cookies")-1, ZEND_ACC_PUBLIC TSRMLS_CC); SWOOLE_INIT_CLASS_ENTRY(swoole_http2_response_ce, "swoole_http2_response", "Swoole\\Http2\\Response", NULL); swoole_http2_response_class_entry_ptr = zend_register_internal_class(&swoole_http2_response_ce TSRMLS_CC); SWOOLE_CLASS_ALIAS(swoole_http2_response, "Swoole\\Http2\\Response"); zend_declare_property_long(swoole_http2_response_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http2_response_class_entry_ptr, SW_STRL("statusCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_response_class_entry_ptr, SW_STRL("body")-1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_response_class_entry_ptr, SW_STRL("streamId")-1, ZEND_ACC_PUBLIC TSRMLS_CC); if (cookie_buffer == NULL) { cookie_buffer = swString_new(8192); } }
void swoole_http2_client_coro_init(int module_number TSRMLS_DC) { INIT_CLASS_ENTRY(swoole_http2_client_coro_ce, "Swoole\\Coroutine\\Http2\\Client", swoole_http2_client_methods); swoole_http2_client_coro_class_entry_ptr = zend_register_internal_class(&swoole_http2_client_coro_ce); INIT_CLASS_ENTRY(swoole_http2_request_coro_ce, "Swoole\\Coroutine\\Http2\\Request", NULL); swoole_http2_request_coro_class_entry_ptr = zend_register_internal_class(&swoole_http2_request_coro_ce); if (SWOOLE_G(use_shortname)) { zend_register_class_alias("Co\\Http2\\Client", swoole_http2_client_coro_class_entry_ptr); zend_register_class_alias("Co\\Http2\\Request", swoole_http2_request_coro_class_entry_ptr); } zend_declare_property_long(swoole_http2_client_coro_class_entry_ptr, SW_STRL("type")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http2_client_coro_class_entry_ptr, SW_STRL("errCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http2_client_coro_class_entry_ptr, SW_STRL("statusCode")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_client_coro_class_entry_ptr, SW_STRL("host")-1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http2_client_coro_class_entry_ptr, SW_STRL("port")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http2_client_coro_class_entry_ptr, SW_STRL("sock")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_bool(swoole_http2_client_coro_class_entry_ptr, SW_STRL("reuse")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_http2_client_coro_class_entry_ptr, SW_STRL("reuseCount")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_client_coro_class_entry_ptr, ZEND_STRL("setting"), ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_request_coro_class_entry_ptr, SW_STRL("method")-1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_request_coro_class_entry_ptr, SW_STRL("headers")-1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_request_coro_class_entry_ptr, SW_STRL("data")-1, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_bool(swoole_http2_request_coro_class_entry_ptr, SW_STRL("pipeline")-1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_null(swoole_http2_request_coro_class_entry_ptr, SW_STRL("files")-1, ZEND_ACC_PUBLIC TSRMLS_CC); }
/** * For Http Protocol */ static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event) { swConnection *conn = event->socket; if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE) { if (conn->http_upgrade == 0) { swHttpRequest_free(conn); conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; conn->http_upgrade = 1; } return swPort_onRead_check_length(reactor, port, event); } #ifdef SW_USE_HTTP2 if (conn->http2_stream) { return swPort_onRead_check_length(reactor, port, event); } #endif int n = 0; char *buf; int buf_len; swHttpRequest *request = NULL; swProtocol *protocol = &port->protocol; //new http request if (conn->object == NULL) { request = sw_malloc(sizeof(swHttpRequest)); bzero(request, sizeof(swHttpRequest)); conn->object = request; } else { request = (swHttpRequest *) conn->object; } if (!request->buffer) { request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE); //alloc memory failed. if (!request->buffer) { swReactorThread_onClose(reactor, event); return SW_ERR; } } swString *buffer = request->buffer; recv_data: buf = buffer->str + buffer->length; buf_len = buffer->size - buffer->length; n = swConnection_recv(conn, buf, buf_len, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from connection#%d failed.", event->fd); return SW_OK; case SW_CLOSE: conn->close_errno = errno; goto close_fd; default: return SW_OK; } } else if (n == 0) { close_fd: swHttpRequest_free(conn); swReactorThread_onClose(reactor, event); return SW_OK; } else { buffer->length += n; if (request->method == 0 && swHttpRequest_get_protocol(request) < 0) { if (request->buffer->length < SW_HTTP_HEADER_MAX_SIZE) { return SW_OK; } swWarn("get protocol failed."); #ifdef SW_HTTP_BAD_REQUEST if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST) - 1, 0) < 0) { swSysError("send() failed."); } #endif goto close_fd; } if (request->method > HTTP_PRI) { swWarn("method no support"); goto close_fd; } #ifdef SW_USE_HTTP2 else if (request->method == HTTP_PRI) { conn->http2_stream = 1; swHttp2_send_setting_frame(protocol, conn); if (n == sizeof(SW_HTTP2_PRI_STRING) - 1) { swHttpRequest_free(conn); return SW_OK; } swHttp2_parse_frame(protocol, conn, buf + (sizeof(SW_HTTP2_PRI_STRING) - 1), n - (sizeof(SW_HTTP2_PRI_STRING) - 1)); swHttpRequest_free(conn); return SW_OK; } #endif if (request->content_length == 0) { if (swHttpRequest_get_content_length(request) < 0) { if (memcmp(buffer->str + buffer->length - 4, "\r\n\r\n", 4) == 0) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); return SW_OK; } else if (buffer->size == buffer->length) { swWarn("[0]http header is too long."); goto close_fd; } //wait more data else { goto recv_data; } } else if (request->content_length > (protocol->package_max_length - SW_HTTP_HEADER_MAX_SIZE)) { swWarn("Content-Length is too big, MaxSize=[%d].", protocol->package_max_length - SW_HTTP_HEADER_MAX_SIZE); goto close_fd; } } //http header is not the end if (request->header_length == 0) { if (swHttpRequest_get_header_length(request) < 0) { if (buffer->size == buffer->length) { swWarn("[2]http header is too long."); goto close_fd; } else { goto recv_data; } } } //total length uint32_t request_size = request->content_length + request->header_length; if (request_size > buffer->size && swString_extend(buffer, request_size) < 0) { goto close_fd; } //discard the redundant data if (buffer->length > request_size) { buffer->length = request_size; } if (buffer->length == request_size) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else { #ifdef SW_HTTP_100_CONTINUE //Expect: 100-continue if (swHttpRequest_has_expect_header(request)) { swSendData _send; _send.data = "HTTP/1.1 100 Continue\r\n\r\n"; _send.length = strlen(_send.data); int send_times = 0; direct_send: n = swConnection_send(conn, _send.data, _send.length, 0); if (n < _send.length) { _send.data += n; _send.length -= n; send_times++; if (send_times < 10) { goto direct_send; } else { swWarn("send http header failed"); } } } else { swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n", request->content_length, buffer->length, request->header_length); } #endif goto recv_data; } } return SW_OK; }
/** * For Http Protocol */ static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event) { swConnection *conn = event->socket; swServer *serv = reactor->ptr; if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE) { if (conn->http_upgrade == 0) { swHttpRequest_free(conn); conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; conn->http_upgrade = 1; } return swPort_onRead_check_length(reactor, port, event); } #ifdef SW_USE_HTTP2 if (conn->http2_stream) { _parse_frame: return swPort_onRead_check_length(reactor, port, event); } #endif int n = 0; char *buf; int buf_len; swHttpRequest *request = NULL; swProtocol *protocol = &port->protocol; //new http request if (conn->object == NULL) { request = sw_malloc(sizeof(swHttpRequest)); bzero(request, sizeof(swHttpRequest)); conn->object = request; } else { request = (swHttpRequest *) conn->object; } if (!request->buffer) { request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE); //alloc memory failed. if (!request->buffer) { swReactorThread_onClose(reactor, event); return SW_ERR; } } swString *buffer = request->buffer; recv_data: buf = buffer->str + buffer->length; buf_len = buffer->size - buffer->length; n = swConnection_recv(conn, buf, buf_len, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from connection#%d failed.", event->fd); return SW_OK; case SW_CLOSE: conn->close_errno = errno; goto close_fd; default: return SW_OK; } } else if (n == 0) { close_fd: swHttpRequest_free(conn); swReactorThread_onClose(reactor, event); return SW_OK; } else { buffer->length += n; if (request->method == 0 && swHttpRequest_get_protocol(request) < 0) { if (request->excepted == 0 && request->buffer->length < SW_HTTP_HEADER_MAX_SIZE) { return SW_OK; } swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "get protocol failed."); #ifdef SW_HTTP_BAD_REQUEST_TIP if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST_TIP), 0) < 0) { swSysError("send() failed."); } #endif goto close_fd; } if (request->method > HTTP_PRI) { swWarn("method no support"); goto close_fd; } #ifdef SW_USE_HTTP2 else if (request->method == HTTP_PRI) { conn->http2_stream = 1; swHttp2_send_setting_frame(protocol, conn); if (n == sizeof(SW_HTTP2_PRI_STRING) - 1) { swHttpRequest_free(conn); return SW_OK; } swString *buffer = swServer_get_buffer(serv, event->fd); if (!buffer) { goto close_fd; } swString_append_ptr(buffer, buf + (sizeof(SW_HTTP2_PRI_STRING) - 1), n - (sizeof(SW_HTTP2_PRI_STRING) - 1)); swHttpRequest_free(conn); conn->skip_recv = 1; goto _parse_frame; } #endif //http header is not the end if (request->header_length == 0) { if (swHttpRequest_get_header_length(request) < 0) { if (buffer->size == buffer->length) { swWarn("[2]http header is too long."); goto close_fd; } else { goto recv_data; } } } //http body if (request->content_length == 0) { swTraceLog(SW_TRACE_SERVER, "content-length=%u, keep-alive=%d", request->content_length, request->keep_alive); // content length field not found if (swHttpRequest_get_header_info(request) < 0) { /* the request is really no body */ if (buffer->length == request->header_length) { /** * send static file content directly in the reactor thread */ if (!(serv->enable_static_handler && swPort_http_static_handler(request, conn))) { /** * dynamic request, dispatch to worker */ swReactorThread_dispatch(conn, buffer->str, buffer->length); } swHttpRequest_free(conn); return SW_OK; } else if (buffer->size == buffer->length) { swWarn("[0]http header is too long."); goto close_fd; } /* wait more data */ else { goto recv_data; } } else if (request->content_length > (protocol->package_max_length - request->header_length)) { swWarn("Content-Length is too big, MaxSize=[%d].", protocol->package_max_length - request->header_length); goto close_fd; } } //total length uint32_t request_size = request->header_length + request->content_length; if (request_size > buffer->size && swString_extend(buffer, request_size) < 0) { goto close_fd; } //discard the redundant data if (buffer->length > request_size) { buffer->length = request_size; } if (buffer->length == request_size) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else { #ifdef SW_HTTP_100_CONTINUE //Expect: 100-continue if (swHttpRequest_has_expect_header(request)) { swSendData _send; _send.data = "HTTP/1.1 100 Continue\r\n\r\n"; _send.length = strlen(_send.data); int send_times = 0; direct_send: n = swConnection_send(conn, _send.data, _send.length, 0); if (n < _send.length) { _send.data += n; _send.length -= n; send_times++; if (send_times < 10) { goto direct_send; } else { swWarn("send http header failed"); } } } else { swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n", request->content_length, buffer->length, request->header_length); } #endif goto recv_data; } } return SW_OK; }
int swPort_http_static_handler(swHttpRequest *request, swConnection *conn) { swServer *serv = SwooleG.serv; char *url = request->buffer->str + request->url_offset; char *params = memchr(url, '?', request->url_length); struct { off_t offset; size_t length; char filename[PATH_MAX]; } buffer; char *p = buffer.filename; memcpy(p, serv->document_root, serv->document_root_len); p += serv->document_root_len; uint32_t n = params ? params - url : request->url_length; memcpy(p, url, n); p += n; *p = 0; struct stat file_stat; if (lstat(buffer.filename, &file_stat) < 0) { return SW_FALSE; } if (file_stat.st_size == 0) { return SW_FALSE; } if ((file_stat.st_mode & S_IFMT) != S_IFREG) { return SW_FALSE; } char header_buffer[1024]; swSendData response; response.info.fd = conn->session_id; response.info.type = SW_EVENT_TCP; p = request->buffer->str + request->url_offset + request->url_length + 10; char *pe = request->buffer->str + request->header_length; char *date_if_modified_since = NULL; int length_if_modified_since = 0; int state = 0; for (; p < pe; p++) { switch(state) { case 0: if (strncasecmp(p, SW_STRL("If-Modified-Since")) == 0) { p += sizeof("If-Modified-Since"); state = 1; } break; case 1: if (!isspace(*p)) { date_if_modified_since = p; state = 2; } break; case 2: if (strncasecmp(p, SW_STRL("\r\n")) == 0) { length_if_modified_since = p - date_if_modified_since; goto check_modify_date; } break; default: break; } } char date_[64]; struct tm *tm1; check_modify_date: tm1 = gmtime(&serv->gs->now); strftime(date_, sizeof(date_), "%a, %d %b %Y %H:%M:%S %Z", tm1); char date_last_modified[64]; #ifdef __MACH__ time_t file_mtime = file_stat.st_mtimespec.tv_sec; #elif defined(_WIN32) time_t file_mtime = file_stat.st_mtime; #else time_t file_mtime = file_stat.st_mtim.tv_sec; #endif struct tm *tm2 = gmtime(&file_mtime); strftime(date_last_modified, sizeof(date_last_modified), "%a, %d %b %Y %H:%M:%S %Z", tm2); if (state == 2) { struct tm tm3; char date_tmp[64]; memcpy(date_tmp, date_if_modified_since, length_if_modified_since); date_tmp[length_if_modified_since] = 0; char *date_format = NULL; if (strptime(date_tmp, SW_HTTP_RFC1123_DATE_GMT, &tm3) != NULL) { date_format = SW_HTTP_RFC1123_DATE_GMT; } else if (strptime(date_tmp, SW_HTTP_RFC1123_DATE_UTC, &tm3) != NULL) { date_format = SW_HTTP_RFC1123_DATE_UTC; } else if (strptime(date_tmp, SW_HTTP_RFC850_DATE, &tm3) != NULL) { date_format = SW_HTTP_RFC850_DATE; } else if (strptime(date_tmp, SW_HTTP_ASCTIME_DATE, &tm3) != NULL) { date_format = SW_HTTP_ASCTIME_DATE; } if (date_format && mktime(&tm3) - (int) timezone >= file_mtime) { response.length = response.info.len = snprintf(header_buffer, sizeof(header_buffer), "HTTP/1.1 304 Not Modified\r\n" "%s" "Date: %s\r\n" "Last-Modified: %s\r\n" "Server: %s\r\n\r\n", request->keep_alive ? "Connection: keep-alive\r\n" : "", date_, date_last_modified, SW_HTTP_SERVER_SOFTWARE ); response.data = header_buffer; swReactorThread_send(&response); goto _finish; } } response.length = response.info.len = snprintf(header_buffer, sizeof(header_buffer), "HTTP/1.1 200 OK\r\n" "%s" "Content-Length: %ld\r\n" "Content-Type: %s\r\n" "Date: %s\r\n" "Last-Modified: %s\r\n" "Server: %s\r\n\r\n", request->keep_alive ? "Connection: keep-alive\r\n" : "", (long) file_stat.st_size, swoole_get_mime_type(buffer.filename), date_, date_last_modified, SW_HTTP_SERVER_SOFTWARE); response.data = header_buffer; #ifdef HAVE_TCP_NOPUSH if (conn->tcp_nopush == 0) { if (swSocket_tcp_nopush(conn->fd, 1) == -1) { swWarn("swSocket_tcp_nopush() failed. Error: %s[%d]", strerror(errno), errno); } conn->tcp_nopush = 1; } #endif swReactorThread_send(&response); buffer.offset = 0; buffer.length = file_stat.st_size; response.info.type = SW_EVENT_SENDFILE; response.length = response.info.len = sizeof(swSendFile_request) + buffer.length + 1; response.data = (void*) &buffer; swReactorThread_send(&response); _finish: if (!request->keep_alive) { response.info.type = SW_EVENT_CLOSE; response.length = 0; response.data = NULL; swReactorThread_send(&response); } return SW_TRUE; }
void swoole_mysql_coro_init(int module_number TSRMLS_DC) { INIT_CLASS_ENTRY(swoole_mysql_coro_ce, "Swoole\\Coroutine\\MySQL", swoole_mysql_coro_methods); swoole_mysql_coro_class_entry_ptr = zend_register_internal_class(&swoole_mysql_coro_ce TSRMLS_CC); INIT_CLASS_ENTRY(swoole_mysql_coro_statement_ce, "Swoole\\Coroutine\\MySQL\\Statement", swoole_mysql_coro_statement_methods); swoole_mysql_coro_statement_class_entry_ptr = zend_register_internal_class( &swoole_mysql_coro_statement_ce TSRMLS_CC); INIT_CLASS_ENTRY(swoole_mysql_coro_exception_ce, "Swoole\\Coroutine\\MySQL\\Exception", NULL); swoole_mysql_coro_exception_class_entry_ptr = sw_zend_register_internal_class_ex(&swoole_mysql_coro_exception_ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); if (SWOOLE_G(use_shortname)) { sw_zend_register_class_alias("Co\\MySQL", swoole_mysql_coro_class_entry_ptr); sw_zend_register_class_alias("Co\\MySQL\\Statement", swoole_mysql_coro_statement_class_entry_ptr); sw_zend_register_class_alias("Co\\MySQL\\Exception", swoole_mysql_coro_exception_class_entry_ptr); } zend_declare_property_string(swoole_mysql_coro_class_entry_ptr, SW_STRL("serverInfo") - 1, "", ZEND_ACC_PRIVATE TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_class_entry_ptr, SW_STRL("sock") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_bool(swoole_mysql_coro_class_entry_ptr, SW_STRL("connected") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_string(swoole_mysql_coro_class_entry_ptr, SW_STRL("connect_error") - 1, "", ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_class_entry_ptr, SW_STRL("connect_errno") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_class_entry_ptr, SW_STRL("affected_rows") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_class_entry_ptr, SW_STRL("insert_id") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_string(swoole_mysql_coro_class_entry_ptr, SW_STRL("error") - 1, "", ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_class_entry_ptr, SW_STRL("errno") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_statement_class_entry_ptr, SW_STRL("affected_rows") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_statement_class_entry_ptr, SW_STRL("insert_id") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_string(swoole_mysql_coro_statement_class_entry_ptr, SW_STRL("error") - 1, "", ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_long(swoole_mysql_coro_statement_class_entry_ptr, SW_STRL("errno") - 1, 0, ZEND_ACC_PUBLIC TSRMLS_CC); }
/** * For Http Protocol */ static int swPort_onRead_http(swReactor *reactor, swListenPort *port, swEvent *event) { swConnection *conn = event->socket; #ifdef SW_USE_OPENSSL if (swPort_check_ssl_state(port, conn) < 0) { goto close_fd; } #endif if (conn->websocket_status >= WEBSOCKET_STATUS_HANDSHAKE) { if (conn->object != NULL) { swHttpRequest_free(conn); conn->websocket_status = WEBSOCKET_STATUS_ACTIVE; } return swPort_onRead_check_length(reactor, port, event); } int n = 0; char *buf; int buf_len; swHttpRequest *request = NULL; swProtocol *protocol = &port->protocol; //new http request if (conn->object == NULL) { request = sw_malloc(sizeof(swHttpRequest)); bzero(request, sizeof(swHttpRequest)); conn->object = request; } else { request = (swHttpRequest *) conn->object; } if (!request->buffer) { request->buffer = swString_new(SW_HTTP_HEADER_MAX_SIZE); //alloc memory failed. if (!request->buffer) { swReactorThread_onClose(reactor, event); return SW_ERR; } } swString *buffer = request->buffer; recv_data: buf = buffer->str + buffer->length; buf_len = buffer->size - buffer->length; n = swConnection_recv(conn, buf, buf_len, 0); if (n < 0) { switch (swConnection_error(errno)) { case SW_ERROR: swSysError("recv from connection#%d failed.", event->fd); return SW_OK; case SW_CLOSE: goto close_fd; default: return SW_OK; } } else if (n == 0) { close_fd: swHttpRequest_free(conn); swReactorThread_onClose(reactor, event); return SW_OK; } else { conn->last_time = SwooleGS->now; buffer->length += n; if (request->method == 0 && swHttpRequest_get_protocol(request) < 0) { if (request->buffer->length < SW_HTTP_HEADER_MAX_SIZE) { return SW_OK; } swWarn("get protocol failed."); #ifdef SW_HTTP_BAD_REQUEST if (swConnection_send(conn, SW_STRL(SW_HTTP_BAD_REQUEST) - 1, 0) < 0) { swSysError("send() failed."); } #endif goto close_fd; } swTrace("request->method=%d", request->method); //DELETE if (request->method == HTTP_DELETE) { if (request->content_length == 0 && swHttpRequest_have_content_length(request) == SW_FALSE) { goto http_no_entity; } else { goto http_entity; } } //GET HEAD OPTIONS else if (request->method == HTTP_GET || request->method == HTTP_HEAD || request->method == HTTP_OPTIONS) { http_no_entity: if (memcmp(buffer->str + buffer->length - 4, "\r\n\r\n", 4) == 0) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else if (buffer->size == buffer->length) { swWarn("http header is too long."); goto close_fd; } //wait more data else { goto recv_data; } } //POST PUT HTTP_PATCH else if (request->method == HTTP_POST || request->method == HTTP_PUT || request->method == HTTP_PATCH) { http_entity: if (request->content_length == 0) { if (swHttpRequest_get_content_length(request) < 0) { if (buffer->size == buffer->length) { swWarn("http header is too long."); goto close_fd; } else { goto recv_data; } } else if (request->content_length > protocol->package_max_length) { swWarn("content-length more than the package_max_length[%d].", protocol->package_max_length); goto close_fd; } } uint32_t request_size = 0; //http header is not the end if (request->header_length == 0) { if (buffer->size == buffer->length) { swWarn("http header is too long."); goto close_fd; } if (swHttpRequest_get_header_length(request) < 0) { goto recv_data; } request_size = request->content_length + request->header_length; } else { request_size = request->content_length + request->header_length; } if (request_size > buffer->size && swString_extend(buffer, request_size) < 0) { goto close_fd; } //discard the redundant data if (buffer->length > request_size) { buffer->length = request_size; } if (buffer->length == request_size) { swReactorThread_dispatch(conn, buffer->str, buffer->length); swHttpRequest_free(conn); } else { #ifdef SW_HTTP_100_CONTINUE //Expect: 100-continue if (swHttpRequest_has_expect_header(request)) { swSendData _send; _send.data = "HTTP/1.1 100 Continue\r\n\r\n"; _send.length = strlen(_send.data); int send_times = 0; direct_send: n = swConnection_send(conn, _send.data, _send.length, 0); if (n < _send.length) { _send.data += n; _send.length -= n; send_times++; if (send_times < 10) { goto direct_send; } else { swWarn("send http header failed"); } } } else { swTrace("PostWait: request->content_length=%d, buffer->length=%zd, request->header_length=%d\n", request->content_length, buffer->length, request->header_length); } #endif goto recv_data; } } else { swWarn("method no support"); goto close_fd; } } return SW_OK; }