Skip to content

Commit

Permalink
Fix the issue of incorrect multipart content-type on the HTTP server.
Browse files Browse the repository at this point in the history
  • Loading branch information
matyhtf committed Jul 25, 2024
1 parent a3123af commit fe43ef0
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 10 deletions.
2 changes: 1 addition & 1 deletion ext-src/php_swoole_cxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ class CharPtr {
str_ = estrndup(str, len);
}

void assign_tolower(char *str, size_t len) {
void assign_tolower(const char *str, size_t len) {
release();
str_ = zend_str_tolower_dup(str, len);
}
Expand Down
4 changes: 3 additions & 1 deletion ext-src/php_swoole_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,15 @@ struct Context {
multipart_parser *mt_parser;

uint16_t input_var_num;
char *current_header_name;
const char *current_header_name;
size_t current_header_name_len;
char *current_input_name;
size_t current_input_name_len;
char *current_form_data_name;
size_t current_form_data_name_len;
zval *current_multipart_header;
const char *tmp_content_type;
size_t tmp_content_type_len;
String *form_data_buffer;

std::string upload_tmp_dir;
Expand Down
25 changes: 17 additions & 8 deletions ext-src/swoole_http_request.cc
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ static int http_request_on_query_string(swoole_http_parser *parser, const char *

static int http_request_on_header_field(swoole_http_parser *parser, const char *at, size_t length) {
HttpContext *ctx = (HttpContext *) parser->data;
ctx->current_header_name = (char *) at;
ctx->current_header_name = at;
ctx->current_header_name_len = length;
return 0;
}
Expand Down Expand Up @@ -342,7 +342,7 @@ bool swoole_http_token_list_contains_value(const char *at, size_t length, const
static int http_request_on_header_value(swoole_http_parser *parser, const char *at, size_t length) {
HttpContext *ctx = (HttpContext *) parser->data;
zval *zheader = ctx->request.zheader;
char *header_name = ctx->current_header_name;
const char *header_name = ctx->current_header_name;
size_t header_len = ctx->current_header_name_len;

if (ctx->parse_cookie && SW_STRCASEEQ(header_name, header_len, "cookie")) {
Expand Down Expand Up @@ -546,7 +546,11 @@ static int multipart_body_on_header_value(multipart_parser *p, const char *at, s
zval *z_multipart_header = sw_malloc_zval();
array_init(z_multipart_header);

add_assoc_string(z_multipart_header, "type", (char *) "");
if (ctx->tmp_content_type) {
add_assoc_stringl(z_multipart_header, "type", ctx->tmp_content_type, ctx->tmp_content_type_len);
} else {
add_assoc_string(z_multipart_header, "type", (char *) "");
}
add_assoc_string(z_multipart_header, "tmp_name", (char *) "");
add_assoc_long(z_multipart_header, "size", 0);

Expand All @@ -563,11 +567,16 @@ static int multipart_body_on_header_value(multipart_parser *p, const char *at, s
ctx->current_multipart_header = z_multipart_header;
}
zval_ptr_dtor(&tmp_array);
} else if (SW_STRCASEEQ(header_name, header_len, "content-type") && ctx->current_multipart_header) {
zval *z_multipart_header = ctx->current_multipart_header;
zval *zerr = zend_hash_str_find(Z_ARRVAL_P(z_multipart_header), ZEND_STRL("error"));
if (zerr && Z_TYPE_P(zerr) == IS_LONG && Z_LVAL_P(zerr) == HTTP_UPLOAD_ERR_OK) {
add_assoc_stringl(z_multipart_header, "type", (char *) at, length);
} else if (SW_STRCASEEQ(header_name, header_len, "content-type")) {
if (ctx->current_multipart_header) {
zval *z_multipart_header = ctx->current_multipart_header;
zval *zerr = zend_hash_str_find(Z_ARRVAL_P(z_multipart_header), ZEND_STRL("error"));
if (zerr && Z_TYPE_P(zerr) == IS_LONG && Z_LVAL_P(zerr) == HTTP_UPLOAD_ERR_OK) {
add_assoc_stringl(z_multipart_header, "type", (char *) at, length);
}
} else {
ctx->tmp_content_type = at;
ctx->tmp_content_type_len = length;
}
} else if (SW_STRCASEEQ(header_name, header_len, SW_HTTP_UPLOAD_FILE)) {
zval *z_multipart_header = ctx->current_multipart_header;
Expand Down
70 changes: 70 additions & 0 deletions tests/swoole_http_server/tmp-content-type.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
--TEST--
swoole_http_server: tmp content-type
--SKIPIF--
<?php
require __DIR__ . '/../include/skipif.inc';
?>
--FILE--
<?php
require __DIR__ . '/../include/bootstrap.php';
require_once TESTS_LIB_PATH . '/vendor/autoload.php';

use Swoole\Runtime;
use GuzzleHttp\Client as GuzzleHttpClient;
use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;

use function Swoole\Coroutine\run;

Runtime::enableCoroutine(SWOOLE_HOOK_NATIVE_CURL);

register_shutdown_function(function (){
phpt_show_usage();
});

$pm = new SwooleTest\ProcessManager;
$pm->parentFunc = function () use ($pm) {
run(function () use ($pm) {
$client = new GuzzleHttpClient();
$baseUrl = 'http://127.0.0.1:' . $pm->getFreePort();
$res = $client->post($baseUrl . '/', [
'multipart' => [
[
'name' => 'file',
'contents' => fopen(__FILE__, 'r'),
'filename' => basename(__FILE__),
'headers' => ['Content-Type' => 'application/php-script']
],
],
]);

$status = $res->getStatusCode();
$body = $res->getBody()->getContents();
Assert::eq($status, 200);
$result = json_decode($body, true);
Assert::eq($result['file']['name'], basename(__FILE__));
Assert::eq($result['file']['type'], 'application/php-script');
});
echo "DONE\n";
$pm->kill();
};

$pm->childFunc = function () use ($pm) {
$http = new Server('127.0.0.1', $pm->getFreePort(), SWOOLE_BASE);
$http->set([
'log_file' => '/dev/null',
]);
$http->on('workerStart', function () use ($pm) {
$pm->wakeup();
});
$http->on('request', function (Request $request, Response $response) use ($http) {
$response->end(json_encode($request->files));
});
$http->start();
};
$pm->childFirst();
$pm->run();
?>
--EXPECT--
DONE

0 comments on commit fe43ef0

Please sign in to comment.