这里有一个很奇怪的问题...我开发了一个小型的https客户端,从一个公共API获取一些数据(不需要认证)问题是当我试图获取数据时,我总是得到一个404 HTTP错误,即使我确信我在发送给服务器的GET命令中请求的资源的路径是正确的。如果我尝试用curl获取相同的资源(使用完全相同的路径),它可以毫无问题地工作,这一事实也证实了这一点。
这是我编写的https客户端(下面是我在网上找到的一个示例):
int main(int argc, char **argv)
{
char *message=NULL;
char *CAfile=NULL;
int port=443;
char *host_and_port=NULL;
unsigned int len=0;
SSL *ssl=NULL;
BIO *bio=NULL;
SSL_CTX *ctx=NULL;
int r = 0;
ssize_t rr = -1;
ssize_t length=0;
unsigned char *buffer=NULL;
ssize_t l=0;
unsigned char *https_stream=NULL;
ssize_t https_stream_size=0;
CAfile=strdup("mycert.pem");
message=strdup("GET /path1/path2?arg1=val1&arg2=val2 HTTP/1.0\r\nHost: myhost.com\r\n\r\n");
host_and_port=strdup("myhost.com:443");
SSL_load_error_strings();
SSL_library_init();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
if (!(ctx = SSL_CTX_new(TLS_client_method())))
{
fprintf(stderr,"The creation of a new SSL_CTX object failed.\n");
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s:", ERR_error_string(ERR_get_error(), NULL));
return -1;
}
if (!(r = SSL_CTX_load_verify_locations(ctx, CAfile, NULL)))
{
fprintf(stderr,"Unable to load the trust certificate from file: %s\n",CAfile);
fprintf(stderr, "Error: %s\n",ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s:",ERR_error_string(ERR_get_error(), NULL));
return -1;
}
/* Setting up the BIO SSL object */
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, &ssl);
if (!ssl)
{
fprintf(stderr,"Unable to allocate SSL pointer.\n");
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s:",ERR_error_string(ERR_get_error(), NULL));
return -1;
}
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
/* Attempt to connect */
BIO_set_conn_hostname(bio, host_and_port);
/* Verify the connection opened and perform the handshake */
if (BIO_do_connect(bio) < 1)
{
fprintf(stderr,"Unable to connect BIO. %s\n",host_and_port);
fprintf(stderr, "Error: %s\n",ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s:",ERR_error_string(ERR_get_error(), NULL));
return -1;
}
length=strlen(message);
rr=-1;
while (rr < 0)
{
rr = BIO_write(bio, message, length);
if (rr <= 0)
{
if (!BIO_should_retry(bio))
{
fprintf(stderr,"BIO_write should retry.\n");
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s:", ERR_error_string(ERR_get_error(), NULL));
return -1;
}
}
}
if (rr!=length)
{
fprintf(stderr,"Error in sending encripted message.\n");
return -1;
}
if (buffer)
{
free(buffer);
buffer=NULL;
}
if (!(https_stream=malloc(sizeof(char))))
{
fprintf(stderr, "Allocation memory failed (https_stream string), code=%d (%s)\n",errno, strerror(errno));
return -1;
}
https_stream[0]=0;
https_stream_size=0;
length=4096;
if (!(buffer=malloc(length*sizeof(char))))
{
fprintf(stderr, "Allocation memory failed (buffer string), code=%d (%s)\n",errno, strerror(errno));
return -1;
}
bzero(buffer,length);
rr=-1;
while((rr = BIO_read(bio, buffer, length)))
{
if (rr<0)
if (!BIO_should_retry(bio))
{
fprintf(stderr,"BIO_read should retry.\n");
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s:", ERR_error_string(ERR_get_error(), NULL));
return -1;
}
l=https_stream_size;
https_stream_size += rr;
if (!(https_stream=realloc(https_stream,https_stream_size*sizeof(char))))
{
fprintf(stderr, "Re-allocation memory failed (*https_stream string), code=%d (%s)\n",errno, strerror(errno));
return -1;
}
memcpy(https_stream+l,buffer,rr);
bzero(buffer,length);
}
/* clean up the SSL context resources for the encrypted link */
SSL_CTX_free(ctx);
fprintf(stdout,"==========================================\n");
fprintf(stdout,"HTTP Request\n");
fprintf(stdout,"==========================================\n");
fprintf(stdout,"%s\n",message);
fprintf(stdout,"==========================================\n");
fprintf(stdout,"\n");
fprintf(stdout,"Host and port: %s\n",host_and_port);
fprintf(stdout,"\n");
fprintf(stdout,"HTTP Response\n");
fprintf(stdout,"==========================================\n");
fprintf(stdout,"%s\n",https_stream);
fprintf(stdout,"==========================================\n");
if (message)
{
free(message);
message=NULL;
}
if (buffer)
{
free(buffer);
buffer=NULL;
}
if (https_stream)
{
free(https_stream);
https_stream=NULL;
}
if (host_and_port)
{
free(host_and_port);
host_and_port=NULL;
}
return 0;
}
其中,“myhost.com“和“/path 1/path 2?arg 1 =val1&arg2= val 2”分别表示主机的完整地址和要获取的资源的路径。
此代码编译良好(没有任何警告),输出为:
==========================================
HTTP Request
==========================================
GET /path1/path2?arg1=val1&arg2=val2 HTTP/1.0
Host: myhost.com
==========================================
Host and port: myhost.com:443
HTTP Response
==========================================
HTTP/1.1 404 Not Found
Content-Length: 231
x-amz-request-id: tx00000000000000019debd-00636e7b40-39e6dd1-default
Accept-Ranges: bytes
Content-Type: application/xml
Date: Fri, 11 Nov 2022 16:41:36 GMT
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-Xss-Protection: 1; mode=block
Content-Security-Policy:script-src: https://www.google-analytics.com https://q.quora.com
Referrer-Policy: no-referrer-when-downgrade
Strict-Transport-Security: max-age=31536000;includeSubDomains;preload
<?xml version="1.0" encoding="UTF-8"?><Error><Code>NoSuchBucket</Code><BucketName>myhost.com</BucketName><RequestId>tx00000000000000019debd-00636e7b40-39e6dd1-default</RequestId><HostId>39e6dd1-default-default</HostId></Error>
==========================================
因此,正如您所看到的,我得到了HTTP错误代码404。现在,如果在同一台计算机上使用curl访问同一台服务器上的同一资源,则会得到:
curl -v --http1.0 "https://myhost.com/path1/path2?arg1=val1&arg2=val2"
* Trying <host_IP>:443...
* Connected to myhost.com (<host_IP>) port 443 (#0)
* ALPN: offers http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* CAfile: none
* CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
...
* SSL certificate verify ok.
> GET /path1/path2?arg1=val1&arg2=val2 HTTP/1.0
> Host: myhost.com
> User-Agent: curl/7.85.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< server: nginx/1.23.2
< date: Fri, 11 Nov 2022 17:40:16 GMT
< content-type: application/json; charset=utf-8
< transfer-encoding: chunked
< x-powered-by: Express
< set-cookie: 3866fdcd36aeaae468ebac902177effe=5f9cbf1450843f212673d67cb86a2f9a; path=/; HttpOnly
< cache-control: private
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< X-Xss-Protection: 1; mode=block
< Content-Security-Policy:script-src: https://www.google-analytics.com https://q.quora.com
< Referrer-Policy: no-referrer-when-downgrade
< Strict-Transport-Security: max-age=31536000;includeSubDomains;preload
<
正如你所看到的,curl可以正确地返回HTTP代码200。这证明了在服务器上,我所寻找的资源实际上在指定的路径上是可用的(这是我在curl和我的客户端中指定的相同路径)。因此,我写的客户端中应该有什么错误,不幸的是我不能弄清楚。有什么想法吗?任何帮助都是非常欢迎的。
很遗憾,我无法访问服务器日志文件....
提前感谢您的可用性!
1条答案
按热度按时间jogvjijk1#
我怀疑curl自动把协议升级到了1.1。
您要包括主机标头,因此请尝试使用1.1。