Общий HTTP-сервер, который просто выводит POST-запросы?

Вопрос или проблема

Я ищу инструмент командной строки, который будет слушать на заданном порту, с радостью принимать каждую HTTP POST запрос и выводить его.

Я хочу использовать его в тестовых целях, т.е. для тестирования клиентов, которые отправляют HTTP POST запросы.

Это значит, что я ищу аналог curl -F (который я могу использовать для отправки тестовых HTTP POST запросов на HTTP сервер).

Возможно, что-то вроде socat TCP4-LISTEN:80,fork,bind=127.0.0.1 ... – но socat недостаточен, потому что он не поддерживает HTTP.

Я искал это сам и наткнулся на Node.js http-echo-server:

npm install http-echo-server -g
PORT=8081 http-echo-server

Он принимает все запросы и выводит полный запрос, включая заголовки, в командную строку.

Простые инструменты командной строки, такие как nc, socat, похоже, не способны обработать специфические HTTP особенности (чанки, кодировки передачи и т.д.). В результате это может привести к неожиданному поведению по сравнению с взаимодействием с настоящим веб-сервером. Поэтому моя первая мысль – поделиться кратчайшим способом настройки небольшого веб-сервера и заставить его делать то, что вам нужно: выводить весь вывод.

Самый короткий способ, который я мог придумать, используя Python Tornado:

#!/usr/bin/env python

import tornado.ioloop
import tornado.web
import pprint

class MyDumpHandler(tornado.web.RequestHandler):
    def post(self):
        pprint.pprint(self.request)
        pprint.pprint(self.request.body)

if __name__ == "__main__":
    tornado.web.Application([(r"/.*", MyDumpHandler),]).listen(8080)
    tornado.ioloop.IOLoop.instance().start()

Замените строку pprint, чтобы выводить только конкретные поля, которые вам нужны, например self.request.body или self.request.headers. В приведенном выше примере он слушает на порту 8080 на всех интерфейсах.

Альтернатив этому множество. web.py, Bottle и т.д.

(Я достаточно ориентирован на Python, извините)


Если вам не нравится его способ вывода, просто запустите его и попробуйте tcpdump вот так:

tcpdump -i lo 'tcp[32:4] = 0x484f535420'

чтобы увидеть реальный необработанный дамп всех HTTP-POST запросов. В качестве альтернативы просто запустите Wireshark.

Используйте nc (произносится как “netcat“).

Вы говорите ему, на каком порту слушать

nc -kl 8888

Затем в отдельном окне терминала отправьте ему запрос

curl localhost:8888 -d hello=world

и он выведет данные, которые вы ему отправили, в данном случае HTTP запрос:

POST / HTTP/1.1
Host: localhost:8888
User-Agent: curl/7.84.0
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencoded

hello=world

Опция -k означает, что он будет слушать запросы и выводить их бесконечно. Без этой опции (т.е. nc -l 8888) он завершит работу после первого запроса.

https://hub.docker.com/r/jmalloc/echo-server/

Запустите

$ docker run -t --rm -p 8080:8080 jmalloc/echo-server
Не удалось найти изображение 'jmalloc/echo-server:latest' локально
latest: Загруска из jmalloc/echo-server
fbf67b0844fa: Полная загрузка
Digest: sha256:617a99b927c3b761621681eb4716582260391c0853b6da904e0f9f1d37785e7a
Статус: Загружено новое изображение для jmalloc/echo-server:latest
Echo сервер слушает на порту 8080

Post

$ curl -XPOST -H"ThisTook: 2 minutes to find" localhost:8080/asdf
Запрос обслуживается a2d8fa109b92

HTTP/1.1 POST /asdf

Host: localhost:8080
User-Agent: curl/7.54.0
Accept: */*
Thistook: 2 minutes to find

Стандартная библиотека Python поставляется с комплектом, т.е. она даже включает пакет HTTP сервера, который можно использовать для написания простого дампера HTTP запросов:

#!/usr/bin/env python3

import argparse
import http.server
import json
import sys

class Dumper(http.server.BaseHTTPRequestHandler):
    def do_GET(self, method='GET'):
        print(f'\n{method} {self.path}\n{self.headers}')
        self.send_response(200)
        self.end_headers()

    def do_DELETE(self):
        return self.do_GET('DELETE')

    def do_POST(self, method='POST'):
        n = int(self.headers.get('content-length', 0))
        body = self.rfile.read(n)
        print(f'\n{method} {self.path}\n{self.headers}{body}\n')
        if self.headers.get('content-type') == 'application/json':
            d = json.loads(body)
            print(json.dumps(d, indent=4, sort_keys=True))
            print()
        self.send_response(200)
        self.end_headers()

    def do_PUT(self):
        return self.do_POST('PUT')

    def log_message(self, format, *args):
        pass

Некоторые шаблоны:


def main():
    p = argparse.ArgumentParser(description='Дампить HTTP запросы в stdout')
    p.add_argument('address', help='адрес привязки')
    p.add_argument('port', type=int, help='порт привязки')
    xs = p.parse_args();
    s = http.server.HTTPServer((xs.address, xs.port), Dumper)
    s.serve_forever()

if __name__ == '__main__':
    sys.exit(main())

Смотрите также: мой gist

У меня была такая же необходимость (получить поток POST сообщений) и я не смог заставить netcat работать. Я пробовал различные коды (200, 201, и 204) и заголовки (Location:, Content-type:, и Content-length:) комбинации, но ничего не работало.

Но решение @gertvdijk на Python сработало, так что я перехватил пакеты с помощью Wireshark во время его работы и обнаружил, что Tornado отправлял код 200 с заголовками “Connection: close” и “Content-length: 0”.

Так что я попробовал снова с netcat… и это сработало:

while true; do echo -e 'HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: close\r\n\r\n' | nc -l 8000; done

Ответ или решение

Для тестирования HTTP-клиентов, которые отправляют POST-запросы, может быть полезен простой HTTP-сервер, который будет принимать каждый входящий POST-запрос и выводить его содержимое. В данной статье мы рассмотрим несколько различных подходов, как это можно реализовать в командной строке или с помощью кода.

1. Использование Python и библиотеки Tornado

Самый быстрый и популярный способ создать HTTP-сервер для этой цели — использовать фреймворк Tornado. Ниже представлен простой пример кода, который принимает POST-запросы и выводит их детали на консоль:

#!/usr/bin/env python

import tornado.ioloop
import tornado.web
import pprint

class MyDumpHandler(tornado.web.RequestHandler):
    def post(self):
        # Вывод информации о запросе
        pprint.pprint(self.request.headers)
        pprint.pprint(self.request.body)

if __name__ == "__main__":
    tornado.web.Application([(r"/.*", MyDumpHandler),]).listen(8080)
    tornado.ioloop.IOLoop.instance().start()

Этот сервер будет слушать на порту 8080 и выводить заголовки и тело каждого POST-запроса, полученного на любом пути.

2. Python HTTP-сервер стандартной библиотеки

Если вы хотите использовать стандартные библиотеки Python, можно воспользоваться встроенным HTTP-сервером. Вот пример кода, который также выводит содержимое запросов:

#!/usr/bin/env python3

import argparse
import http.server
import json
import sys

class Dumper(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length)
        print(f'\nPOST {self.path}\n{self.headers}\n{body.decode()}\n')
        self.send_response(200)
        self.end_headers()

def main():
    parser = argparse.ArgumentParser(description='Dump HTTP requests to stdout')
    parser.add_argument('address', help='bind address')
    parser.add_argument('port', type=int, help='bind port')
    args = parser.parse_args()
    server = http.server.HTTPServer((args.address, args.port), Dumper)
    server.serve_forever()

if __name__ == '__main__':
    sys.exit(main())

Запустив этот код, вы сможете принимать POST-запросы и выводить их детали на стандартный вывод.

3. Использование Docker и echo-сервера

Если вы предпочитаете использовать Docker, вы можете запустить готовый echo-сервер, который будет слушать на определенном порту. Просто выполните команду:

docker run -t --rm -p 8080:8080 jmalloc/echo-server

После этого вы сможете отправлять POST-запросы на localhost:8080, и сервер будет выводить их содержимое.

4. Использование Netcat (nc)

Для простых случаев можно использовать утилиту nc (netcat). Однако она не полностью поддерживает протокол HTTP. Пример команды:

nc -kl 8888

Затем, в другом терминале, вы можете отправить запрос:

curl -X POST -d "hello=world" localhost:8888

Этот подход работает, но помните, что netcat имеет ограничения при работе с HTTP-запросами, особенно с различными типами кодирования и заголовками.

Заключение

Выбор подхода зависит от ваших специфических требований и предпочтений. Для простоты и расширяемости рекомендуется использовать Python с Tornado или встроенный HTTP-сервер. Docker-решение — отличный вариант для быстрой настройки окружения. Netcat может подойти для простого тестирования, но с ограничениями. Выберите метод, который наилучшим образом соответствует вашим нуждам при тестировании вашего HTTP-клиента.

Оцените материал
Добавить комментарий

Капча загружается...