bud_client_error_t bud_client_prepend_proxyline(bud_client_t* client) { int r; const char* family; char proxyline[256]; if (client->family == AF_INET) { family = "TCP4"; } else if (client->family == AF_INET6) { family = "TCP6"; } else { r = -1; goto fatal; } r = snprintf(proxyline, sizeof(proxyline), client->config->proxyline_fmt, family, client->host, ntohs(client->port)); ASSERT(0 <= r && r < (int) sizeof(proxyline), "Client proxyline overflow"); r = ringbuffer_insert(&client->backend.output, 0, proxyline, (size_t) r); if (r != 0) goto fatal; return bud_client_ok(&client->backend); fatal: return bud_client_error(bud_error_num(kBudErrClientProxyline, r), &client->backend); }
bud_client_error_t bud_client_spdy_xforward(bud_client_t* client, const char* protocol, unsigned int protocol_len) { int major; int minor; int r; unsigned char frame[256]; /* Detect protocol version */ major = -1; minor = 0; switch (protocol_len) { case 1: if (protocol[0] == '3') major = 3; else if (protocol[0] == '2') major = 2; break; case 3: if (strncmp(protocol, "3.1", protocol_len) == 0) { major = 3; minor = 1; } break; default: break; } /* We are done by now */ client->xforward.crlf = 2; if (major == -1) goto skip; assert(12 + client->host_len <= sizeof(frame)); frame[0] = 0x80; frame[1] = major; *(uint16_t*) (frame + 2) = ntohs(kSpdyXForwardFrameType); /* Frame and Host lengths */ *(uint32_t*) (frame + 4) = htonl(4 + client->host_len); *(uint32_t*) (frame + 8) = htonl(client->host_len); /* Copy hostname */ memcpy(frame + 12, client->host, client->host_len); /* Prepend it to output data */ r = ringbuffer_insert(&client->backend.output, 0, (const char*) frame, (size_t) 12 + client->host_len); if (r != 0) { return bud_client_error(bud_error(kBudErrClientXForwardInsert), &client->backend); } skip: return bud_client_ok(&client->backend); }
bud_client_error_t bud_client_http_xforward(bud_client_t* client) { char* out; size_t avail; size_t off; char xforward[256]; int r; out = ringbuffer_read_next(&client->backend.output, &avail); /* Not enough data yet */ if (avail <= client->xforward.skip) goto done; /* Find first CRLF */ for (off = client->xforward.skip; off < avail; off++) { static char* crlf = "\r\n"; char cur; cur = out[off]; /* Reset on mismatch */ if (cur != crlf[client->xforward.crlf]) { client->xforward.crlf = 0; continue; } /* Move forward */ if (++client->xforward.crlf == 2) { off++; break; } } client->xforward.skip = off; if (!bud_client_xforward_done(client)) goto done; /* Format header */ r = snprintf(xforward, sizeof(xforward), "X-Forwarded-For: %s\r\n", client->host); /* Shift data and insert xforward header */ r = ringbuffer_insert(&client->backend.output, client->xforward.skip, xforward, (size_t) r); if (r != 0) { return bud_client_error(bud_error(kBudErrClientXForwardInsert), &client->backend); } done: return bud_client_ok(&client->backend); }
bud_client_error_t bud_client_prepend_proxyline(bud_client_t* client) { int r; const char* family; char proxyline[1024]; bud_config_proxyline_t type; /* * Client should both handshake and connect to backend in order to * be able to send proper proxyline */ ASSERT(client->proxyline_waiting > 0, "Too many prepend proxyline calls"); if (--client->proxyline_waiting != 0) return bud_client_ok(); type = client->selected_backend->proxyline; if (type == kBudProxylineNone) return bud_client_ok(); if (client->remote.family == AF_INET) { family = "TCP4"; } else if (client->remote.family == AF_INET6) { family = "TCP6"; } else { r = -1; goto fatal; } if (type == kBudProxylineHAProxy) { r = snprintf(proxyline, sizeof(proxyline), client->config->proxyline_fmt.haproxy, family, client->remote.host, ntohs(client->remote.port)); } else { const char* cn; cn = bud_client_get_peer_name(client); r = snprintf(proxyline, sizeof(proxyline), client->config->proxyline_fmt.json, family, client->remote.host, ntohs(client->remote.port), cn != NULL ? '"' : 'f', cn != NULL ? cn : "als", cn != NULL ? '"' : 'e'); } ASSERT(0 <= r && r < (int) sizeof(proxyline), "Client proxyline overflow"); r = ringbuffer_insert(&client->backend.output, 0, proxyline, (size_t) r); if (r != 0) goto fatal; return bud_client_ok(&client->backend); fatal: return bud_client_error(bud_error_num(kBudErrClientProxyline, r), &client->backend); }
int main() { int i; int j; int r; int after; ssize_t len; char* ptr; data = malloc(TEST_DATA_SIZE); assert(data != NULL); ringbuffer_init(&rb); /* Fill test data */ for (i = 0; i < TEST_DATA_SIZE; i++) data[i] = (i * i) % 137; /* Fill ringbuffer */ i = 0; after = 0; while (i < TEST_DATA_SIZE - TEST_INSERT_LEN) { if (after) len = TEST_DATA_SIZE - i - TEST_INSERT_LEN; else len = TEST_INSERT_OFF - i; ptr = ringbuffer_write_ptr(&rb, &len); ASSERT(ptr != NULL); /* Always make progress */ ASSERT(len > 0); if (after) memcpy(ptr, data + i + TEST_INSERT_LEN, len); else memcpy(ptr, data + i, len); i += len; r = ringbuffer_write_append(&rb, len); ASSERT(r == 0); if (i == TEST_INSERT_OFF) after = 1; } ASSERT(ringbuffer_size(&rb) == TEST_DATA_SIZE - TEST_INSERT_LEN); /* Insert stuff */ ringbuffer_insert(&rb, TEST_INSERT_OFF, data + TEST_INSERT_OFF, TEST_INSERT_LEN); /* Read from it */ i = 0; while (i < TEST_DATA_SIZE) { len = TEST_DATA_SIZE - i; ptr = ringbuffer_read_next(&rb, &len); ASSERT(ptr != NULL); /* Always make progress */ ASSERT(len > 0); for (j = 0; j < len; j++) ASSERT(ptr[j] == data[i + j]); ringbuffer_read_skip(&rb, len); i += len; } /* Destroy it */ ringbuffer_destroy(&rb); return 0; }