Разбирайте необработанные HTTP-заголовки

У меня есть строка raw HTTP и я хотел бы представлять поля в объекте. Есть ли способ разобрать отдельные заголовки из строки HTTP?

'GET /search?sourceid=chrome&ie=UTF-8&q=ergterst HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.45 Safari/534.13\r\nAccept-Encoding: gzip,deflate,sdch\r\nAvail-Dictionary: GeNLY2f-\r\nAccept-Language: en-US,en;q=0.8\r\n [...]' 

3 Solutions collect form web for “Разбирайте необработанные HTTP-заголовки”

В стандартной библиотеке есть отличные инструменты как для разбора заголовков RFC 821, так и для синтаксического анализа целых HTTP-запросов. Вот пример строки запроса (обратите внимание, что Python рассматривает ее как одну большую строку, даже если мы ее разбиваем на несколько строк для удобства чтения), которые мы можем использовать для моих примеров:

 request_text = ( 'GET /who/ken/trust.html HTTP/1.1\r\n' 'Host: cm.bell-labs.com\r\n' 'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n' 'Accept: text/html;q=0.9,text/plain\r\n' '\r\n' ) 

Как указывает @TryPyPy, вы можете использовать mimetools.Message для синтаксического анализа заголовков – хотя мы должны добавить, что результирующий объект Message действует как словарь заголовков, как только вы закончите его создание:

 # Ignore the request line and parse only the headers from mimetools import Message from StringIO import StringIO request_line, headers_alone = request_text.split('\r\n', 1) headers = Message(StringIO(headers_alone)) print len(headers) # -> "3" print headers.keys() # -> ['accept-charset', 'host', 'accept'] print headers['Host'] # -> "cm.bell-labs.com" 

Но это, конечно, игнорирует строку запроса или заставляет вас разобрать ее самостоятельно. Оказывается, есть гораздо лучшее решение.

Стандартная библиотека будет анализировать HTTP для вас, если вы используете свой BaseHTTPRequestHandler . Хотя его документация немного неясна – проблема со всем набором инструментов HTTP и URL в стандартной библиотеке – все, что вам нужно сделать, чтобы выполнить синтаксический анализ строки: (a) заверните свою строку в StringIO() , (b ) читайте raw_requestline чтобы он был готов к анализу и (c) захватил все коды ошибок, возникающие во время разбора, вместо того, чтобы позволить ему попытаться записать их обратно клиенту (поскольку у нас его нет!).

Итак, вот наша специализация класса Standard Library:

 from BaseHTTPServer import BaseHTTPRequestHandler from StringIO import StringIO class HTTPRequest(BaseHTTPRequestHandler): def __init__(self, request_text): self.rfile = StringIO(request_text) self.raw_requestline = self.rfile.readline() self.error_code = self.error_message = None self.parse_request() def send_error(self, code, message): self.error_code = code self.error_message = message 

Опять же, я хочу, чтобы пользователи стандартной библиотеки поняли, что разбор HTTP должен быть разбит таким образом, что нам не нужно было писать девять строк кода, чтобы правильно его называть, но что вы можете сделать? Вот как вы могли бы использовать этот простой класс:

 # Using this new class is really easy! request = HTTPRequest(request_text) print request.error_code # None (check this first) print request.command # "GET" print request.path # "/who/ken/trust.html" print request.request_version # "HTTP/1.1" print len(request.headers) # 3 print request.headers.keys() # ['accept-charset', 'host', 'accept'] print request.headers['host'] # "cm.bell-labs.com" 

Если во время разбора есть ошибка, то error_code не будет None :

 # Parsing can result in an error code and message request = HTTPRequest('GET\r\nHeader: Value\r\n\r\n') print request.error_code # 400 print request.error_message # "Bad request syntax ('GET')" 

Я предпочитаю использовать стандартную библиотеку так, потому что я подозреваю, что они уже столкнулись и разрешили любые случаи краев, которые могут укусить меня, если я попытаюсь перепрограммировать спецификацию Интернета самостоятельно с помощью регулярных выражений.

Кажется, что это нормально, если вы GET линию GET :

 import mimetools from StringIO import StringIO he = "Host: www.google.com\r\nConnection: keep-alive\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.45 Safari/534.13\r\nAccept-Encoding: gzip,deflate,sdch\r\nAvail-Dictionary: GeNLY2f-\r\nAccept-Language: en-US,en;q=0.8\r\n" m = mimetools.Message(StringIO(he)) print m.headers 

Способ анализа вашего примера и добавления информации из первой строки в объект будет выглядеть так:

 import mimetools from StringIO import StringIO he = 'GET /search?sourceid=chrome&ie=UTF-8&q=ergterst HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\n' # Pop the first line for further processing request, he = he.split('\r\n', 1) # Get the headers m = mimetools.Message(StringIO(he)) # Add request information m.dict['method'], m.dict['path'], m.dict['http-version'] = request.split() print m['method'], m['path'], m['http-version'] print m['Connection'] print m.headers print m.dict 

mimetools устарел с Python 2.3 и полностью удален из Python 3 ( ссылка ).

Вот как вы должны сделать в Python 3:

 import email import io import pprint # […] request_line, headers_alone = request_text.split('\r\n', 1) message = email.message_from_file(io.StringIO(headers_alone)) headers = dict(message.items()) pprint.pprint(headers, width=160) 
  • Попытка входа в quora с использованием механизации
  • Библиотека запросов Python перенаправляет новый URL-адрес
  • Как получить IP-адрес клиента от SimpleHTTPServer
  • Python 3 Получить страницу HTTP
  • Получение Gunicorn для работы на порту 80
  • Использование декодеров ETag / Last-Modified с использованием общих представлений Django на основе классов
  • Как загрузить удаленный javascript в контекст SpiderMonkey?
  • Как отлаживать HTTP-запрос в сценарии модульного тестирования в Python
  • Python - лучший язык программирования в мире.