in src/incoming.c [143:234]
static apr_status_t perform_peek_protocol(serf_incoming_t *client)
{
const char h2prefix[] = "PRI * HTTP/2.0\r\n\r\n";
const apr_size_t h2prefixlen = sizeof(h2prefix) - 1;
const char *data;
apr_size_t len;
struct peek_data_t
{
char buffer[sizeof(h2prefix)];
int read;
} *peek_data = client->protocol_baton;
apr_status_t status;
if (!peek_data) {
status = serf_bucket_peek(client->pump.stream, &data, &len);
if (len > h2prefixlen)
len = h2prefixlen;
if (len && memcmp(data, h2prefix, len) != 0) {
/* This is not HTTP/2 */
serf_incoming_set_framing_type(client,
SERF_CONNECTION_FRAMING_TYPE_HTTP1);
/* Easy out */
serf_bucket_destroy(client->proto_peek_bkt);
client->proto_peek_bkt = NULL;
return APR_SUCCESS;
}
else if (len == h2prefixlen) {
/* We have HTTP/2 */
serf_incoming_set_framing_type(client,
SERF_CONNECTION_FRAMING_TYPE_HTTP2);
serf_bucket_destroy(client->proto_peek_bkt);
client->proto_peek_bkt = NULL;
return APR_SUCCESS;
}
peek_data = serf_bucket_mem_calloc(client->allocator,
sizeof(*peek_data));
client->protocol_baton = peek_data;
}
do {
status = serf_bucket_read(client->pump.stream,
h2prefixlen - peek_data->read,
&data, &len);
if (SERF_BUCKET_READ_ERROR(status))
return status;
memcpy(peek_data->buffer + peek_data->read, data, len);
peek_data->read += len;
if (len && memcmp(data, h2prefix, len)) {
/* This is not HTTP/2 */
serf_incoming_set_framing_type(client,
SERF_CONNECTION_FRAMING_TYPE_HTTP1);
/* Put data ahead of other data and do the usual thing */
serf_bucket_aggregate_prepend(client->proto_peek_bkt,
serf_bucket_simple_own_create(
peek_data->buffer,
peek_data->read,
client->allocator));
return APR_SUCCESS;
}
else if (len == h2prefixlen) {
/* We have HTTP/2 */
serf_incoming_set_framing_type(client,
SERF_CONNECTION_FRAMING_TYPE_HTTP2);
/* Put data ahead of other data and do the usual thing */
serf_bucket_aggregate_prepend(client->proto_peek_bkt,
serf_bucket_simple_own_create(
peek_data->buffer,
peek_data->read,
client->allocator));
return APR_SUCCESS;
}
} while (status == APR_SUCCESS);
return status;
}