J'ai écrit un module proxy miniature en Python 3 qui se place simplement entre mon navigateur et le web. Mon but est de simplement proxyer le trafic allant et venant. Un des comportements du programme est de sauvegarder les réponses du site web que je reçois dans un répertoire local.
Tout fonctionne comme prévu, à l'exception du simple fait que l'utilisation de socket.recv()
dans une boucle semble ne jamais donner le blanc bytes
impliqué dans l'objet exemples fournis dans la documentation . Pratiquement tous les exemples en ligne parlent de la chaîne vide qui passe par le socket lorsque le serveur le ferme.
Je suppose qu'il se passe quelque chose via l'en-tête keep-alive, où le serveur distant nunca ferme la socket à moins que son propre seuil de dépassement de temps ne soit atteint. Est-ce correct ? Si oui, comment puis-je détecter la fin de l'envoi d'une charge utile ? Observer que les données reçues sont plus petites que la taille des morceaux que j'ai déclarée ne fonctionne pas du tout, en raison de la façon dont le TCP fonctionne.
Pour démontrer, le code suivant ouvre un socket vers un fichier image sur le serveur web de Google. J'ai copié la chaîne de requête réelle des propres requêtes de mon navigateur. L'exécution du code (rappelez-vous, Python 3 !) montre que les données binaires de l'image sont reçues jusqu'à la fin, mais le code n'est jamais capable de frapper la requête break
déclaration. Ce n'est qu'au moment où le serveur ferme le socket (après environ 3 minutes d'inactivité) que ce code atteint réellement l'instruction print
à la fin du fichier.
Comment diable peut-on contourner ce problème ? Mon objectif est de ne pas modifier le comportement des requêtes de mon navigateur - je ne veux pas avoir à définir la valeur de l'attribut keep-alive
à l'en-tête false
ou quelque chose d'éclatant comme ça. La solution consiste-t-elle à utiliser de vilains timeouts (par le biais de socket.settimeout()
) ? Cela semble risible, mais je ne vois pas ce qu'on pourrait faire d'autre.
Merci d'avance.
import socket
remote_host = 'www.google.com'
remote_port = 80
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host, remote_port))
remote_socket.sendall(b'GET http://www.google.com/images/logos/ps_logo2a_cp.png HTTP/1.1\r\nHost: www.google.com\r\nCache-Control: max-age=0\r\nPragma: no-cache\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.794.0 Safari/535.1\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n\r\n')
content = b''
while True:
msg = remote_socket.recv(1024)
if not msg:
break
print(msg)
content += msg
print("DONE: %d" % len(content))