spdycat: Add -d option to POST data
This commit is contained in:
parent
28489fd6a8
commit
ae8e5b7a95
|
@ -25,6 +25,7 @@
|
|||
#include "spdylay_config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
@ -60,6 +61,10 @@
|
|||
#include "HtmlParser.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
# define O_BINARY (0)
|
||||
#endif // O_BINARY
|
||||
|
||||
namespace spdylay {
|
||||
|
||||
struct Config {
|
||||
|
@ -76,6 +81,7 @@ struct Config {
|
|||
std::string keyfile;
|
||||
int window_bits;
|
||||
std::map<std::string,std::string> headers;
|
||||
std::string datafile;
|
||||
Config():null_out(false), remote_name(false), verbose(false),
|
||||
get_assets(false), stat(false), no_tls(false),
|
||||
spdy_version(-1), timeout(-1), window_bits(-1)
|
||||
|
@ -201,13 +207,20 @@ struct Request {
|
|||
http_parser_url u;
|
||||
spdylay_gzip *inflater;
|
||||
HtmlParser *html_parser;
|
||||
const spdylay_data_provider *data_prd;
|
||||
int64_t data_length;
|
||||
int64_t data_offset;
|
||||
// Recursion level: 0: first entity, 1: entity linked from first entity
|
||||
int level;
|
||||
RequestStat stat;
|
||||
std::string status;
|
||||
Request(const std::string& uri, const http_parser_url &u, int level = 0)
|
||||
Request(const std::string& uri, const http_parser_url &u,
|
||||
const spdylay_data_provider *data_prd, int64_t data_length,
|
||||
int level = 0)
|
||||
: uri(uri), u(u),
|
||||
inflater(0), html_parser(0), level(level)
|
||||
inflater(0), html_parser(0), data_prd(data_prd),
|
||||
data_length(data_length),data_offset(0),
|
||||
level(level)
|
||||
{}
|
||||
|
||||
~Request()
|
||||
|
@ -330,13 +343,15 @@ struct SpdySession {
|
|||
hostport = ss.str();
|
||||
}
|
||||
bool add_request(const std::string& uri, const http_parser_url& u,
|
||||
const spdylay_data_provider *data_prd,
|
||||
int64_t data_length,
|
||||
int level = 0)
|
||||
{
|
||||
if(path_cache.count(uri)) {
|
||||
return false;
|
||||
} else {
|
||||
path_cache.insert(uri);
|
||||
reqvec.push_back(new Request(uri, u, level));
|
||||
reqvec.push_back(new Request(uri, u, data_prd, data_length, level));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -355,7 +370,8 @@ void submit_request(Spdylay& sc, const std::string& hostport,
|
|||
{
|
||||
std::string path = req->make_reqpath();
|
||||
int r = sc.submit_request(get_uri_field(req->uri.c_str(), req->u, UF_SCHEMA),
|
||||
hostport, path, headers, 3, req);
|
||||
hostport, path, headers, 3, req->data_prd,
|
||||
req->data_length, req);
|
||||
assert(r == 0);
|
||||
}
|
||||
|
||||
|
@ -375,7 +391,8 @@ void update_html_parser(SpdySession *spdySession, Request *req,
|
|||
fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_SCHEMA) &&
|
||||
fieldeq(uri.c_str(), u, req->uri.c_str(), req->u, UF_HOST) &&
|
||||
porteq(uri.c_str(), u, req->uri.c_str(), req->u)) {
|
||||
spdySession->add_request(uri, u, req->level+1);
|
||||
// No POST data for assets
|
||||
spdySession->add_request(uri, u, 0, 0, req->level+1);
|
||||
submit_request(*spdySession->sc, spdySession->hostport, config.headers,
|
||||
spdySession->reqvec.back());
|
||||
}
|
||||
|
@ -717,6 +734,29 @@ int communicate(const std::string& host, uint16_t port,
|
|||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
ssize_t file_read_callback
|
||||
(spdylay_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, int *eof,
|
||||
spdylay_data_source *source, void *user_data)
|
||||
{
|
||||
Request *req = (Request*)spdylay_session_get_stream_user_data
|
||||
(session, stream_id);
|
||||
int fd = source->fd;
|
||||
ssize_t r;
|
||||
while((r = pread(fd, buf, length, req->data_offset)) == -1 &&
|
||||
errno == EINTR);
|
||||
if(r == -1) {
|
||||
return SPDYLAY_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
} else {
|
||||
if(r == 0) {
|
||||
*eof = 1;
|
||||
} else {
|
||||
req->data_offset += r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
int run(char **uris, int n)
|
||||
{
|
||||
spdylay_session_callbacks callbacks;
|
||||
|
@ -739,6 +779,25 @@ int run(char **uris, int n)
|
|||
uint16_t prev_port = 0;
|
||||
int failures = 0;
|
||||
SpdySession spdySession;
|
||||
int data_fd = -1;
|
||||
spdylay_data_provider data_prd;
|
||||
struct stat data_stat;
|
||||
|
||||
if(!config.datafile.empty()) {
|
||||
data_fd = open(config.datafile.c_str(), O_RDONLY | O_BINARY);
|
||||
if(data_fd == -1) {
|
||||
std::cerr << "Could not open file " << config.datafile << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(fstat(data_fd, &data_stat) == -1) {
|
||||
close(data_fd);
|
||||
std::cerr << "Could not stat file " << config.datafile << std::endl;
|
||||
return 1;
|
||||
}
|
||||
data_prd.source.fd = data_fd;
|
||||
data_prd.read_callback = file_read_callback;
|
||||
}
|
||||
|
||||
for(int i = 0; i < n; ++i) {
|
||||
http_parser_url u;
|
||||
std::string uri = strip_fragment(uris[i]);
|
||||
|
@ -758,7 +817,8 @@ int run(char **uris, int n)
|
|||
prev_host = get_uri_field(uri.c_str(), u, UF_HOST);
|
||||
prev_port = port;
|
||||
}
|
||||
spdySession.add_request(uri, u);
|
||||
spdySession.add_request(uri, u, data_fd == -1 ? 0 : &data_prd,
|
||||
data_stat.st_size);
|
||||
}
|
||||
}
|
||||
if(!spdySession.reqvec.empty()) {
|
||||
|
@ -772,7 +832,7 @@ int run(char **uris, int n)
|
|||
|
||||
void print_usage(std::ostream& out)
|
||||
{
|
||||
out << "Usage: spdycat [-Oansv23] [-t <SECONDS>] [-w <WINDOW_BITS>] [--cert=<CERT>]\n"
|
||||
out << "Usage: spdycat [-Oadnsv23] [-t <SECONDS>] [-w <WINDOW_BITS>] [--cert=<CERT>]\n"
|
||||
<< " [--key=<KEY>] [--no-tls] <URI>..."
|
||||
<< std::endl;
|
||||
}
|
||||
|
@ -807,6 +867,8 @@ void print_help(std::ostream& out)
|
|||
<< " must be in PEM format.\n"
|
||||
<< " --no-tls Disable SSL/TLS. Use -2 or -3 to specify\n"
|
||||
<< " SPDY protocol version to use.\n"
|
||||
<< " -d, --data=<FILE> Post FILE to server. If - is given, data\n"
|
||||
<< " will be read from stdin.\n"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
@ -829,10 +891,11 @@ int main(int argc, char **argv)
|
|||
{"help", no_argument, 0, 'h' },
|
||||
{"header", required_argument, 0, 'H' },
|
||||
{"no-tls", no_argument, &flag, 3 },
|
||||
{"data", required_argument, 0, 'd' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "OanhH:v23st:w:", long_options,
|
||||
int c = getopt_long(argc, argv, "Oad:nhH:v23st:w:", long_options,
|
||||
&option_index);
|
||||
if(c == -1) {
|
||||
break;
|
||||
|
@ -906,6 +969,9 @@ int main(int argc, char **argv)
|
|||
case 's':
|
||||
config.stat = true;
|
||||
break;
|
||||
case 'd':
|
||||
config.datafile = strcmp("-", optarg) == 0 ? "/dev/stdin" : optarg;
|
||||
break;
|
||||
case '?':
|
||||
exit(EXIT_FAILURE);
|
||||
case 0:
|
||||
|
|
|
@ -144,6 +144,8 @@ int Spdylay::submit_request(const std::string& scheme,
|
|||
const std::string& path,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
uint8_t pri,
|
||||
const spdylay_data_provider *data_prd,
|
||||
int64_t data_length,
|
||||
void *stream_user_data)
|
||||
{
|
||||
enum eStaticHeaderPosition
|
||||
|
@ -158,7 +160,7 @@ int Spdylay::submit_request(const std::string& scheme,
|
|||
};
|
||||
|
||||
const char *static_nv[] = {
|
||||
":method", "GET",
|
||||
":method", data_prd ? "POST" : "GET",
|
||||
":path", path.c_str(),
|
||||
":version", "HTTP/1.1",
|
||||
":scheme", scheme.c_str(),
|
||||
|
@ -170,6 +172,9 @@ int Spdylay::submit_request(const std::string& scheme,
|
|||
int hardcoded_entry_count = sizeof(static_nv) / sizeof(*static_nv);
|
||||
int header_count = headers.size();
|
||||
int total_entry_count = hardcoded_entry_count + header_count * 2;
|
||||
if(data_prd) {
|
||||
++total_entry_count;
|
||||
}
|
||||
|
||||
const char **nv = new const char*[total_entry_count + 1];
|
||||
|
||||
|
@ -180,6 +185,14 @@ int Spdylay::submit_request(const std::string& scheme,
|
|||
|
||||
int pos = hardcoded_entry_count;
|
||||
|
||||
std::string content_length_str;
|
||||
if(data_prd) {
|
||||
std::stringstream ss;
|
||||
ss << data_length;
|
||||
content_length_str = ss.str();
|
||||
nv[pos++] = "content-length";
|
||||
nv[pos++] = content_length_str.c_str();
|
||||
}
|
||||
while( i != end ) {
|
||||
const char *key = (*i).first.c_str();
|
||||
const char *value = (*i).second.c_str();
|
||||
|
@ -201,7 +214,8 @@ int Spdylay::submit_request(const std::string& scheme,
|
|||
}
|
||||
nv[pos] = NULL;
|
||||
|
||||
int r = spdylay_submit_request(session_, pri, nv, NULL, stream_user_data);
|
||||
int r = spdylay_submit_request(session_, pri, nv, data_prd,
|
||||
stream_user_data);
|
||||
|
||||
delete [] nv;
|
||||
|
||||
|
|
|
@ -58,7 +58,10 @@ public:
|
|||
int submit_request(const std::string& scheme,
|
||||
const std::string& hostport, const std::string& path,
|
||||
const std::map<std::string,std::string>& headers,
|
||||
uint8_t pri, void *stream_user_data);
|
||||
uint8_t pri,
|
||||
const spdylay_data_provider *data_prd,
|
||||
int64_t data_length,
|
||||
void *stream_user_data);
|
||||
int submit_settings(int flags, spdylay_settings_entry *iv, size_t niv);
|
||||
bool would_block();
|
||||
void* user_data();
|
||||
|
|
Loading…
Reference in New Issue