1933
1942
HttpSM::process_srv_info(HostDBInfo * r)
1935
Debug("dns_srv", "beginning process_srv_info");
1944
DebugSM("dns_srv", "beginning process_srv_info");
1937
1946
SRVHosts s(r); /* handled by conversion constructor */
1938
1947
char new_host[MAXDNAME];
1940
1949
/* we didnt get any SRV records, continue w normal lookup */
1941
1950
if (!r->srv_count) {
1942
Debug("dns_srv", "No SRV records were available, continuing to lookup %s", t_state.dns_info.lookup_name);
1943
strncpy(&new_host[0], t_state.dns_info.lookup_name, MAXDNAME);
1944
new_host[MAXDNAME - 1] = '\0';
1951
DebugSM("dns_srv", "No SRV records were available, continuing to lookup %s", t_state.dns_info.lookup_name);
1952
ink_strlcpy(new_host, t_state.dns_info.lookup_name, sizeof(new_host));
1948
1956
s.getWeightedHost(&new_host[0]);
1950
1958
if (*new_host == '\0') {
1951
Debug("dns_srv", "Weighted host returned was NULL or blank!, using %s as origin", t_state.dns_info.lookup_name);
1952
strncpy(&new_host[0], t_state.dns_info.lookup_name, MAXDNAME);
1953
new_host[MAXDNAME - 1] = '\0';
1959
DebugSM("dns_srv", "Weighted host returned was NULL or blank!, using %s as origin", t_state.dns_info.lookup_name);
1960
ink_strlcpy(new_host, t_state.dns_info.lookup_name, sizeof(new_host));
1955
Debug("dns_srv", "Weighted host now: %s", new_host);
1962
DebugSM("dns_srv", "Weighted host now: %s", new_host);
1958
Debug("dns_srv", "ending process_srv_info SRV stuff; moving on to lookup origin host");
1965
DebugSM("dns_srv", "ending process_srv_info SRV stuff; moving on to lookup origin host");
1961
Debug("http_seq", "[HttpStateMachineGet::process_srv_info] Doing DNS Lookup based on SRV %s", new_host);
1968
DebugSM("http_seq", "[HttpStateMachineGet::process_srv_info] Doing DNS Lookup based on SRV %s", new_host);
1963
1970
int server_port = t_state.current.server ? t_state.current.server->port : t_state.server_info.port;
1965
1972
HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_hostdb_lookup);
1967
1974
if (t_state.api_txn_dns_timeout_value != -1) {
1968
Debug("http_timeout", "beginning DNS lookup. allowing %d mseconds for DNS", t_state.api_txn_dns_timeout_value);
1975
DebugSM("http_timeout", "beginning DNS lookup. allowing %d mseconds for DNS", t_state.api_txn_dns_timeout_value);
1971
1978
Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this,
3811
3865
if (t_state.host_db_info.app.http_data.last_failure != 0) {
3812
3866
t_state.host_db_info.app.http_data.last_failure = 0;
3867
ats_ip_port_cast(&t_state.current.server->addr) = htons(t_state.current.server->port);
3813
3868
issue_update |= 1;
3814
Debug("http", "[%" PRId64 "] hostdb update marking IP: %u.%u.%u.%u (port %d) as up",
3869
char addrbuf[INET6_ADDRPORTSTRLEN];
3870
DebugSM("http", "[%" PRId64 "] hostdb update marking IP: %s as up",
3816
((unsigned char *) &t_state.current.server->ip)[0],
3817
((unsigned char *) &t_state.current.server->ip)[1],
3818
((unsigned char *) &t_state.current.server->ip)[2],
3819
((unsigned char *) &t_state.current.server->ip)[3], t_state.current.server->port);
3872
ats_ip_nptop(&t_state.current.server->addr.sa, addrbuf, sizeof(addrbuf)));
3823
3876
if (issue_update) {
3824
hostDBProcessor.setby(t_state.current.server->name, 0,
3825
t_state.current.server->port, t_state.current.server->ip, &t_state.host_db_info.app);
3877
hostDBProcessor.setby(t_state.current.server->name,
3878
strlen(t_state.current.server->name),
3879
&t_state.current.server->addr.sa,
3880
&t_state.host_db_info.app
3884
char addrbuf[INET6_ADDRPORTSTRLEN];
3885
DebugSM("http", "server info = %s", ats_ip_nptop(&t_state.current.server->addr.sa, addrbuf, sizeof(addrbuf)));
3832
// this function first checks if cached response has Accept-Ranges and
3833
// Content-Length header and is HTTP/1.1. && There is no other plugins
3834
// hooked to TS_HTTP_RESPONSE_TRANSFORM_HOOK.
3835
// Then setup Range transformation if necessary
3890
HttpSM::parse_range_and_compare(MIMEField *field, int64_t content_length)
3892
// note: unsatisfiable_range is initialized to true in constructor
3893
int prev_good_range = -1;
3897
int nr = 0; // number of valid ranges, also index to range array.
3901
if (content_length <= 0)
3904
ink_assert(field != NULL);
3907
value = csv.get_first(field, &value_len);
3910
value = csv.get_next(&value_len);
3916
value = csv.get_first(field, &value_len);
3918
// Currently HTTP/1.1 only defines bytes Range
3919
if (ptr_len_ncmp(value, value_len, "bytes=", 6) == 0) {
3920
t_state.ranges = NEW(new RangeRecord[n_values]);
3921
value += 6; // skip leading 'bytes='
3925
bool valid = true; // found valid range.
3926
// If delimiter '-' is missing
3927
if (!(e = (const char *) memchr(value, '-', value_len))) {
3928
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
3929
t_state.num_range_fields = -1;
3933
/* [amc] We should do a much better job of checking the values
3934
from mime_parse_int64 to detect invalid range values (e.g.
3935
non-numeric). Those need to be handled differently than
3936
missing values. My reading of the spec is that ATS should go to
3937
RANGE_NONE in such a case.
3940
t_state.ranges[nr]._start = ((s==e)?-1:mime_parse_int64(s, e));
3944
e = value + value_len;
3945
if ( e && *(e-1) == '-') { //open-ended Range: bytes=10-\r\n\r\n should be supported
3946
t_state.ranges[nr]._end = -1;
3949
t_state.ranges[nr]._end = mime_parse_int64(s, e);
3952
// check and change if necessary whether this is a right entry
3953
if (t_state.ranges[nr]._start >= content_length) {
3957
else if (t_state.ranges[nr]._start == -1 && t_state.ranges[nr]._end > 0) {
3958
if (t_state.ranges[nr]._end > content_length)
3959
t_state.ranges[nr]._end = content_length;
3961
t_state.ranges[nr]._start = content_length - t_state.ranges[nr]._end;
3962
t_state.ranges[nr]._end = content_length - 1;
3965
else if (t_state.ranges[nr]._start >= 0 && t_state.ranges[nr]._end == -1) {
3966
t_state.ranges[nr]._end = content_length - 1;
3968
// "normal" Range - could be wrong if _end<_start
3969
else if (t_state.ranges[nr]._start >= 0 && t_state.ranges[nr]._end >= 0) {
3970
if (t_state.ranges[nr]._start > t_state.ranges[nr]._end)
3971
// [amc] My reading of the spec is that this should cause a change
3972
// to RANGE_NONE because it is syntatically invalid.
3974
else if (t_state.ranges[nr]._end >= content_length)
3975
t_state.ranges[nr]._end = content_length - 1;
3977
// Syntactically invalid range, fail.
3979
// [amc] My reading of the spec is that this should cause a change
3980
// to RANGE_NONE because it is syntatically invalid.
3981
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
3982
t_state.num_range_fields = -1;
3986
// this is a good Range entry
3988
if (t_state.unsatisfiable_range) {
3989
t_state.unsatisfiable_range = false;
3990
// initialize t_state.current_range to the first good Range
3991
t_state.current_range = nr;
3993
// currently we don't handle out-of-order Range entry
3994
else if (prev_good_range >= 0 && t_state.ranges[nr]._start <= t_state.ranges[prev_good_range]._end) {
3995
t_state.not_handle_range = true;
3999
prev_good_range = nr;
4002
value = csv.get_next(&value_len);
4005
// Fail if we didn't find any valid ranges.
4007
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
4008
t_state.num_range_fields = -1;
4010
t_state.num_range_fields = nr;
4015
HttpSM::calculate_output_cl(int64_t content_length, int64_t num_chars)
4019
if (t_state.unsatisfiable_range)
4022
if (t_state.num_range_fields == 1) {
4023
t_state.range_output_cl = t_state.ranges[0]._end - t_state.ranges[0]._start + 1;
4026
for (i = 0; i < t_state.num_range_fields; i++) {
4027
if (t_state.ranges[i]._start >= 0) {
4028
t_state.range_output_cl += boundary_size;
4029
t_state.range_output_cl += sub_header_size + content_length;
4030
t_state.range_output_cl += num_chars_for_int(t_state.ranges[i]._start)
4031
+ num_chars_for_int(t_state.ranges[i]._end) + num_chars + 2;
4032
t_state.range_output_cl += t_state.ranges[i]._end - t_state.ranges[i]._start + 1;
4033
t_state.range_output_cl += 2;
4037
t_state.range_output_cl += boundary_size + 2;
4040
Debug("http_range", "Pre-calculated Content-Length for Range response is %"PRId64, t_state.range_output_cl);
4044
HttpSM::do_range_parse(MIMEField *range_field)
4049
int64_t content_length = t_state.cache_info.object_read->object_size_get();
4050
int64_t num_chars_for_cl = num_chars_for_int(content_length);
4052
parse_range_and_compare(range_field, content_length);
4053
calculate_output_cl(content_length, num_chars_for_cl);
4055
if (t_state.unsatisfiable_range) {
4056
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
4060
if (t_state.not_handle_range) {
4061
t_state.range_setup = HttpTransact::RANGE_NOT_HANDLED;
4065
t_state.range_setup = HttpTransact::RANGE_REQUESTED;
4068
// this function looks for any Range: headers, parses them and either
4069
// sets up a transform processor to handle the request OR defers to the
3837
4072
HttpSM::do_range_setup_if_necessary()
3839
4074
MIMEField *field;
3840
4075
INKVConnInternal *range_trans;
4076
int field_content_type_len = -1;
4077
const char * content_type;
3843
4079
ink_assert(t_state.cache_info.object_read != NULL);
3845
4081
field = t_state.hdr_info.client_request.field_find(MIME_FIELD_RANGE, MIME_LEN_RANGE);
3846
4082
ink_assert(field != NULL);
3848
4084
t_state.range_setup = HttpTransact::RANGE_NONE;
3849
4085
if (t_state.method == HTTP_WKSIDX_GET && t_state.hdr_info.client_request.version_get() == HTTPVersion(1, 1)) {
3850
if (api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == NULL) {
3851
// We may still not do Range if it is out of order Range.
3852
range_trans = transformProcessor.range_transform(mutex, field,
3853
t_state.cache_info.object_read,
3854
&t_state.hdr_info.transform_response, res);
3855
if (range_trans != NULL) {
3856
api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans);
3857
t_state.range_setup = HttpTransact::RANGE_TRANSFORM;
3859
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
3861
t_state.range_setup = HttpTransact::RANGE_NOT_HANDLED;
4086
do_range_parse(field);
4088
if (t_state.range_setup == HttpTransact::RANGE_REQUESTED &&
4089
t_state.num_range_fields > 1 &&
4090
api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == NULL
4093
Debug("http_trans", "Handling multiple Range: requests");
4094
content_type = t_state.cache_info.object_read->response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &field_content_type_len);
4095
//create a Range: transform processor for requests of type Range: bytes=1-2,4-5,10-100 (eg. multiple ranges)
4096
range_trans = transformProcessor.range_transform(mutex,
4098
t_state.unsatisfiable_range,
4099
t_state.num_range_fields,
4100
&t_state.hdr_info.transform_response,
4102
field_content_type_len,
4103
t_state.cache_info.object_read->object_size_get()
4105
if (range_trans != NULL) {
4106
api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans);
4107
t_state.range_setup = HttpTransact::RANGE_REQUESTED;
4109
else { //we couldnt append the transform to our API hooks so bailing
4110
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
4113
else if (t_state.range_setup == HttpTransact::RANGE_REQUESTED && t_state.num_range_fields == 1) {
4114
Debug("http_trans", "Handling single Range: request");
4115
//no op, we will handle this later in the HttpTunnel
4118
t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE;
4214
4468
// We did not manage to get an exisiting session
4215
4469
// and need to open a new connection
4216
unsigned int srv_ip = t_state.current.server->ip;
4217
int srv_port = t_state.current.server->port;
4219
4470
Action *connect_action_handle;
4473
opt.f_blocking_connect = false;
4474
opt.set_sock_param(t_state.txn_conf->sock_recv_buffer_size_out,
4475
t_state.txn_conf->sock_send_buffer_size_out,
4476
t_state.txn_conf->sock_option_flag_out,
4477
t_state.txn_conf->sock_packet_mark_out,
4478
t_state.txn_conf->sock_packet_tos_out);
4480
opt.ip_family = ip_family;
4483
opt.local_port = ua_session->outbound_port;
4485
IpAddr& outbound_ip = AF_INET6 == ip_family ? ua_session->outbound_ip6 : ua_session->outbound_ip4;
4486
if (outbound_ip.isValid()) {
4487
opt.addr_binding = NetVCOptions::INTF_ADDR;
4488
opt.local_ip = outbound_ip;
4489
} else if (ua_session->f_outbound_transparent) {
4490
opt.addr_binding = NetVCOptions::FOREIGN_ADDR;
4491
opt.local_ip = t_state.client_info.addr;
4493
/* If the connection is server side transparent, we can bind to the
4494
port that the client chose instead of randomly assigning one at
4495
the proxy. This is controlled by the 'use_client_source_port'
4496
configuration parameter.
4499
NetVConnection *client_vc = ua_session->get_netvc();
4500
if (t_state.http_config_param->use_client_source_port && NULL != client_vc) {
4501
opt.local_port = client_vc->get_remote_port();
4221
4506
if (t_state.scheme == URL_WKSIDX_HTTPS) {
4222
Debug("http", "calling sslNetProcessor.connect_re");
4507
DebugSM("http", "calling sslNetProcessor.connect_re");
4223
4508
connect_action_handle = sslNetProcessor.connect_re(this, // state machine
4225
srv_port, // host_port
4509
&t_state.current.server->addr.sa, // addr + port
4228
4512
if (t_state.method != HTTP_WKSIDX_CONNECT) {
4229
Debug("http", "calling netProcessor.connect_re");
4513
DebugSM("http", "calling netProcessor.connect_re");
4230
4514
connect_action_handle = netProcessor.connect_re(this, // state machine
4232
srv_port, // host_port
4515
&t_state.current.server->addr.sa, // addr + port
4235
4518
// Setup the timeouts
6387
6667
case HttpTransact::DNS_LOOKUP:
6669
sockaddr const* addr;
6391
if (url_remap_mode == 2 && t_state.first_dns_lookup) {
6392
Debug("cdn", "Skipping DNS Lookup");
6671
if (t_state.api_server_addr_set) {
6672
/* If the API has set the server address before the OS DNS lookup
6673
* then we can skip the lookup
6676
DebugSM("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for API supplied target %s.\n", ats_ip_ntop(&t_state.server_info.addr, ipb, sizeof(ipb)));
6677
// this seems wasteful as we will just copy it right back
6678
ats_ip_copy(t_state.host_db_info.ip(), &t_state.server_info.addr);
6679
t_state.dns_info.lookup_success = true;
6680
call_transact_and_set_next_state(NULL);
6682
} else if (url_remap_mode == 2 && t_state.first_dns_lookup) {
6683
DebugSM("cdn", "Skipping DNS Lookup");
6393
6684
// skip the DNS lookup
6394
// Debug("cdn","If HandleFiltering has already been called.");
6395
6685
t_state.first_dns_lookup = false;
6396
6686
call_transact_and_set_next_state(HttpTransact::HandleFiltering);
6398
6688
} else if (t_state.http_config_param->use_client_target_addr
6399
6689
&& !t_state.url_remap_success
6400
6690
&& t_state.client_info.is_transparent
6401
&& 0 != (addr = t_state.state_machine->ua_session->get_netvc()->get_local_ip())
6691
&& ats_is_ip(addr = t_state.state_machine->ua_session->get_netvc()->get_local_addr())
6403
6694
/* If the connection is client side transparent and the URL
6404
6695
was not remapped, we can use the client destination IP
6405
6696
address instead of doing a DNS lookup. This is controlled
6406
6697
by the 'use_client_target_addr' configuration parameter.
6408
Debug("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for client supplied target %u.%u.%u.%u.\n", PRINT_IP(addr));
6409
t_state.host_db_info.ip() = addr;
6699
DebugSM("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup for client supplied target %s.\n", ats_ip_ntop(addr, ipb, sizeof(ipb)));
6700
ats_ip_copy(t_state.host_db_info.ip(), addr);
6410
6701
t_state.dns_info.lookup_success = true;
6411
6702
call_transact_and_set_next_state(NULL);
6413
6704
} else if (t_state.parent_result.r == PARENT_UNDEFINED && t_state.dns_info.lookup_success) {
6414
6705
// Already set, and we don't have a parent proxy to lookup
6415
ink_assert(t_state.host_db_info.ip());
6416
Debug("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup, provided by plugin");
6706
ink_assert(ats_is_ip(t_state.host_db_info.ip()));
6707
DebugSM("dns", "[HttpTransact::HandleRequest] Skipping DNS lookup, provided by plugin");
6708
call_transact_and_set_next_state(NULL);
6710
} else if (t_state.dns_info.looking_up == HttpTransact::ORIGIN_SERVER &&
6711
t_state.http_config_param->no_dns_forward_to_parent){
6713
if (t_state.cop_test_page)
6714
ats_ip_copy(t_state.host_db_info.ip(), t_state.state_machine->ua_session->get_netvc()->get_local_addr());
6716
t_state.dns_info.lookup_success = true;
6417
6717
call_transact_and_set_next_state(NULL);