@@ -1107,6 +1107,18 @@ def is_good_source(status, server_type):
1107
1107
return is_success (status ) or is_redirection (status )
1108
1108
1109
1109
1110
+ def is_useful_response (resp , node ):
1111
+ if not resp :
1112
+ return False
1113
+ if ('handoff_index' in node
1114
+ and resp .status == 404
1115
+ and resp .headers .get ('x-backend-timestamp' ) is None ):
1116
+ # a 404 from a handoff are not considered authoritative unless they
1117
+ # have an x-backend-timestamp that indicates that there is a tombstone
1118
+ return False
1119
+ return True
1120
+
1121
+
1110
1122
class ByteCountEnforcer (object ):
1111
1123
"""
1112
1124
Enforces that successive calls to file_like.read() give at least
@@ -1956,7 +1968,7 @@ def transfer_headers(self, src_headers, dst_headers):
1956
1968
def generate_request_headers (self , orig_req = None , additional = None ,
1957
1969
transfer = False ):
1958
1970
"""
1959
- Create a list of headers to be used in backend requests
1971
+ Create a dict of headers to be used in backend requests
1960
1972
1961
1973
:param orig_req: the original request sent by the client to the proxy
1962
1974
:param additional: additional headers to send to the backend
@@ -2088,14 +2100,14 @@ def _make_request(self, nodes, part, method, path, headers, query,
2088
2100
if (self .app .check_response (node , self .server_type , resp ,
2089
2101
method , path )
2090
2102
and not is_informational (resp .status )):
2091
- return resp .status , resp .reason , resp .getheaders (), \
2092
- resp .read ()
2103
+ return resp , resp .read (), node
2093
2104
2094
2105
except (Exception , Timeout ):
2095
2106
self .app .exception_occurred (
2096
2107
node , self .server_type ,
2097
2108
'Trying to %(method)s %(path)s' %
2098
2109
{'method' : method , 'path' : path })
2110
+ return None , None , None
2099
2111
2100
2112
def make_requests (self , req , ring , part , method , path , headers ,
2101
2113
query_string = '' , overrides = None , node_count = None ,
@@ -2118,6 +2130,8 @@ def make_requests(self, req, ring, part, method, path, headers,
2118
2130
the returned status of a request.
2119
2131
:param node_count: optional number of nodes to send request to.
2120
2132
:param node_iterator: optional node iterator.
2133
+ :param body: byte string to use as the request body.
2134
+ Try to keep it small.
2121
2135
:returns: a swob.Response object
2122
2136
"""
2123
2137
nodes = GreenthreadSafeIterator (node_iterator or NodeIter (
@@ -2128,25 +2142,25 @@ def make_requests(self, req, ring, part, method, path, headers,
2128
2142
for head in headers :
2129
2143
pile .spawn (self ._make_request , nodes , part , method , path ,
2130
2144
head , query_string , body , self .logger .thread_locals )
2131
- response = []
2145
+ results = []
2132
2146
statuses = []
2133
- for resp in pile :
2134
- if not resp :
2147
+ for resp , body , node in pile :
2148
+ if not is_useful_response ( resp , node ) :
2135
2149
continue
2136
- response .append (resp )
2137
- statuses .append (resp [ 0 ] )
2150
+ results .append (( resp . status , resp . reason , resp . getheaders (), body ) )
2151
+ statuses .append (resp . status )
2138
2152
if self .have_quorum (statuses , node_number ):
2139
2153
break
2140
2154
# give any pending requests *some* chance to finish
2141
2155
finished_quickly = pile .waitall (self .app .post_quorum_timeout )
2142
- for resp in finished_quickly :
2143
- if not resp :
2156
+ for resp , body , node in finished_quickly :
2157
+ if not is_useful_response ( resp , node ) :
2144
2158
continue
2145
- response .append (resp )
2146
- statuses .append (resp [ 0 ] )
2147
- while len (response ) < node_number :
2148
- response .append ((HTTP_SERVICE_UNAVAILABLE , '' , '' , b'' ))
2149
- statuses , reasons , resp_headers , bodies = zip (* response )
2159
+ results .append (( resp . status , resp . reason , resp . getheaders (), body ) )
2160
+ statuses .append (resp . status )
2161
+ while len (results ) < node_number :
2162
+ results .append ((HTTP_SERVICE_UNAVAILABLE , '' , '' , b'' ))
2163
+ statuses , reasons , resp_headers , bodies = zip (* results )
2150
2164
return self .best_response (req , statuses , reasons , bodies ,
2151
2165
'%s %s' % (self .server_type , req .method ),
2152
2166
overrides = overrides , headers = resp_headers )
0 commit comments