Отправка HTTP через сокеты: 400 Bad request

import socket
import re

mysock= socket.socket(socket.AF_INET, socket.SOCK_STREAM)
url=input ("Enter a url: ")
try:
    re.search("^http[s]?://.*?", url)
except:
    print ("Error")

prot, hostdoc= url.split("//")
host, doc= hostdoc.split ("/")
mysock.connect((host, 80))
cmd = 'GET url HTTP/1.0\r\n\r\n'.encode()
mysock.send (cmd)

while True:
    data=mysock.recv(512)
    if len(data)<1:
        break
    print (data.decode(), end='')

mysock.close()

Выдаёт ошибку в Питоне 3.7 (400 Bad request). Ссылки рабочие.

Для решения задачи можно пользоваться только socket. В чём ошибка?


Ответы (1 шт):

Автор решения: gil9red

Нужно добавлять /, например: GET / HTTP/1.0\r\n\r\n (это запрос index), если у вас url будет http://google.ru/search, тогда GET /search HTTP/1.0\r\n\r\n.

Советую парсить url соответствующими инструментами, например urlsplit.

Попробуйте так:

from urllib.parse import urlsplit
import socket
import re

mysock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
url = input("Enter a url: ")
try:
    re.search("^http[s]?://.*?", url)
except:
    print("Error")

result = urlsplit(url)

mysock.connect((result.netloc, 80))

cmd = f'GET {result.path} HTTP/1.0\r\n\r\n'.encode()
mysock.send(cmd)

while True:
    data=mysock.recv(512)
    if len(data)<1:
        break
    print(data.decode(), end='')

mysock.close()

При url = "http://google.ru", успешно вернуло данные:

HTTP/1.0 200 OK\r\nDate: Wed, 25 Mar 2020 19:09:42 GMT\r\nExpires: -1\r\nCache-Control: private ...

Пример работы по шагам:

url = 'http://google.ru/'
result = urlsplit(url)
# SplitResult(scheme='http', netloc='google.ru', path='/', query='', fragment='')

mysock.connect((result.netloc, 80))
# google.ru : 80

cmd = f'GET {result.path} HTTP/1.0\r\n\r\n'.encode()
# b'GET / HTTP/1.0\r\n\r\n'

Еще пример:

url = 'http://google.ru/search'
result = urlsplit(url)
# SplitResult(scheme='http', netloc='google.ru', path='/search', query='', fragment='')
...
cmd = f'GET {result.path} HTTP/1.0\r\n\r\n'.encode()
# b'GET /search HTTP/1.0\r\n\r\n'

UPD.

Для работы сокетов по HTTPS нужен 443 порт, использовать ssl.

Пример:

from urllib.parse import urlsplit
import socket
import ssl


socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
url = 'https://www.coursera.org/robots.txt'

result = urlsplit(url)

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
s_sock = context.wrap_socket(socket, server_hostname=result.netloc)
s_sock.connect((result.netloc, 443))

cmd = f'GET {result.path} HTTP/1.1\r\nHost: {result.netloc}\r\n\r\n'.encode()
s_sock.send(cmd)

while True:
    data = s_sock.recv(512)
    if not data:
        break

    print(data.decode(), end='')

s_sock.close()
→ Ссылка