--- medusa-0.5.4/http_server.py 2004-02-16 14:31:19.000000000 -0600 +++ medusa/http_server.py 2004-02-16 14:40:02.000000000 -0600 @@ -63,10 +63,21 @@ self.outgoing = [] self.reply_headers = { 'Server' : 'Medusa/%s' % VERSION_STRING, 'Date' : http_date.build_http_date (time.time()) } + + # New reply header list (to support multiple + # headers with same name) + self.__reply_header_list = [ + # If the decision is ever made to switch 100% + # the the new api and abandon the old, these + # next two lines should be uncommented. + #('Server' , 'Medusa/%s' % VERSION_STRING), + #('Date' , http_date.build_http_date(time.time())), + ] + self.request_number = http_request.request_counter.increment() self._split_uri = None self._header_cache = {} # -------------------------------------------------- @@ -88,10 +99,135 @@ self.reply_headers.items() ), '\r\n' ) + '\r\n\r\n' + #################################################### + # new reply header management + #################################################### + # These are intended to replace the methods above. + # While I've nodded toward making them play nice + # together (in case someone uses both), I'm really + # assuming that someone will use the new api, or the + # old, not both. + # The old api is left in for backward compatibility, + # since it can't be known if someone is counting on + # the dictionary behavior, and the whole approach of + # using self.__setitem__/__getitem__/has_key is very + # dictionary centric.. Internally, http_server + # is modified to use the new api. + #--------------------------------------------------- + + def add_header(self, name, value): + """ Adds a header to the reply headers """ + self.__reply_header_list.append((name, value)) + + def clear_headers(self): + """ Clears the reply header list """ + + ################################################ + # If the decision is ever made to switch 100% + # the the new api and abandon the old, this + # next bit can go away. + ################################################ + # Remove things from the old dict as well + self.reply_headers.clear() + ################################################ + + self.__reply_header_list[:] = [] + + def remove_header(self, name, value=None): + """ Removes the specified header. + If a value is provided, the name and + value must match to remove the header. + If the value is None, removes all headers + with that name.""" + + found_it = 0 + + ################################################ + # If the decision is ever made to switch 100% + # the the new api and abandon the old, this + # next bit can go away. + ################################################ + # Remove things from the old dict as well + if self.reply_headers.has_key(name): + del self.reply_headers[name] + found_it = 1 + ################################################ + + + if not value is None: + if (name, value) in self.__reply_header_list: + removed_headers = [(name, value)] + found_it = 1 + else: + removed_headers = [] + for h in self.__reply_header_list: + if h[0] == name: + removed_headers.append(h) + found_it = 1 + + if not found_it: + if value is None: + search_value = "%s" % name + else: + search_value = "%s: %s" % (name, value) + + raise LookupError("Header '%s' not found" % search_value) + + for h in removed_headers: + self.__reply_header_list.remove(h) + + + def get_reply_headers(self): + """ Get the tuple of headers that will be used + for generating reply headers""" + header_tuples = self.__reply_header_list[:] + + ################################################ + # If the decision is ever made to switch 100% + # the the new api and abandon the old, this + # next bit can go away. + ################################################ + # The idea here is to insert the headers from + # the old header dict into the new header list, + # UNLESS there's already an entry in the list + # that would have overwritten the dict entry + # if the dict was the only storage... + header_names = [n for n,v in header_tuples] + for n,v in self.reply_headers.items(): + if n not in header_names: + header_tuples.append((n,v)) + header_names.append(n) + # Ok, that should do it. Now, if there were any + # headers in the dict that weren't in the list, + # they should have been copied in. If the name + # was already in the list, we didn't copy it, + # because the value from the dict has been + # 'overwritten' by the one in the list. + ################################################ + + return header_tuples + + def get_reply_header_text(self): + """ Gets the reply header (including status and + additional crlf)""" + + header_tuples = self.get_reply_headers() + + headers = [self.response(self.reply_code)] + headers += ["%s: %s" % h for h in header_tuples] + + return string.join(headers, '\r\n') + '\r\n\r\n' + + #--------------------------------------------------- + # This is the end of the new reply header + # management section. + #################################################### + + # -------------------------------------------------- # split a uri # -------------------------------------------------- # ;?# @@ -220,11 +356,11 @@ # use \r\n as a terminator, and it would just yuck up a lot of stuff) # it's very common for developers to not want to type a version number # when using telnet to debug a server. close_it = 1 - outgoing_header = producers.simple_producer (self.build_reply_header()) + outgoing_header = producers.simple_producer (self.get_reply_header_text()) if close_it: self['Connection'] = 'close' if wrap_in_chunking: