我用 openssl 编写了一个 c 示例代码。您可以关注在函数 iotask() 中实现的 http 原始数据部分。这是示例代码:
/*
compile:
gcc -o fb_photo_upload fb_photo_upload.c -lssl -lcrypto
*/
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
/*
* A image hex array. Let's say if you have a image file called 'myimage.png'.
* then create the hex array as below:
* xxd -i myimage.png > myimage.c
*/
#include "myimage.c"
#define BOUNDARY "boundary12345"
char data_file_header[] = \
"--" BOUNDARY "\r\n" \
"Content-Disposition: form-data; name=\"source\"; filename=\"myimage.png\"\r\n" \
"Content-Type: application/octet-stream\r\n\r\n";
char data_end[] = \
"\r\n--" BOUNDARY "--\r\n";
int iotask(SSL *ssl) {
int i, n, content_len;
char *p;
char writebuf[1024];
char readbuf[1024];
content_len = strlen(data_file_header) + myimage_png_len + strlen(data_end);
p = writebuf;
p += sprintf(p, "POST /v2.9/me/photos?access_token=EAAEcZAcqQqtUBAJyBItkYPLQ0URkZAFPwLXDbPZClSl3BgUvCjJk32Y5QvgNSDuuBMoC4VdoSOknQYJWnx7L2ZCZACPx5ZA2xfPd5ZB7gndtlIXoMkNumzIT0YKQkbqHgoJZBs3LWHw2UHZBbz3W9qm6xN4pKXzIAej1kunoBPGShDAABAB HTTP/1.1\r\n");
p += sprintf(p, "Host: graph.facebook.com\r\n");
p += sprintf(p, "Content-Type: multipart/form-data; boundary=" BOUNDARY "\r\n");
p += sprintf(p, "Content-Length: %d\r\n", content_len);
p += sprintf(p, "\r\n");
SSL_write(ssl, writebuf, strlen(writebuf));
SSL_write(ssl, data_file_header, strlen(data_file_header));
SSL_write(ssl, myimage_png, myimage_png_len);
SSL_write(ssl, data_end, strlen(data_end));
n = SSL_read(ssl, readbuf, sizeof(readbuf));
if (n > 0) {
printf("read %d bytes\r\n", n);
printf("++++++++ result ++++++++\r\n");
printf("%s", readbuf);
printf("-------- result --------\r\n");
}
}
int create_socket(const char *hostname, const int port) {
int sockfd;
struct hostent *host;
struct sockaddr_in dest_addr;
if ( (host = gethostbyname(hostname)) == NULL ) {
printf("cannot resolve hostname\r\n");
abort();
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset( &dest_addr, 0, sizeof(struct sockaddr_in) );
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(port);
dest_addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sockfd, (struct sockaddr *) &dest_addr, sizeof(struct sockaddr)) == -1 ) {
printf("fail to connect\r\n");
}
return sockfd;
}
int main() {
SSL_CTX *ctx;
SSL *ssl;
int sock = 0;
const char *hostname = "graph.facebook.com";
const int port = 443;
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
if( SSL_library_init() < 0 )
printf("fail to init ssl\r\n");
if ( (ctx = SSL_CTX_new(SSLv23_client_method())) == NULL )
printf("fail to create ssl context\r\n");
//Disable SSLv2 and enable all workarounds for buggy servers
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
ssl = SSL_new(ctx);
if ( (sock = create_socket(hostname, 443)) < 0 )
printf("fail to create socket\r\n");
SSL_set_fd(ssl, sock);
if ( SSL_connect(ssl) != 1 )
printf("fail to build ssl session\r\n");
iotask(ssl);
SSL_free(ssl);
close(sock);
SSL_CTX_free(ctx);
printf("end ssl connection\r\n");
return(0);
}