5

This is my code:

# Process connections

print('Listening on port', port)
while True:
    c, addr = s.accept()
    print("Got connection from", addr)
    msg = "<html></html>"

    response_headers = {
        'Content-Type': 'text/html; encoding=utf8',
        'Content-Length': len(msg.encode(encoding="utf-8")),
        'Connection': 'close',
    }

    response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in response_headers.items())

    response_proto = 'HTTP/1.1'
    response_status = '200'
    response_status_text = 'OK' # this can be random

    # sending all this stuff
    r = '%s %s %s' % (response_proto, response_status, response_status_text)
    c.send(r.encode(encoding="utf-8"))
    c.send(response_headers_raw.encode(encoding="utf-8"))
    c.send('\n'.encode(encoding="utf-8")) # to separate headers from body
    c.send(msg.encode(encoding="utf-8"))

    c.close()

When I visit my local ip on the browser, I get an error page that says

ERR_CONNECTION_RESET

What am I doing wrong?

NOTE:

The full code snippet is here:

import socket

# Create socket object and set protocol
s = socket.socket(
    socket.AF_INET, socket.SOCK_STREAM)

# Get name of local machine
host = socket.gethostname()
port = 80

# Bind
s.bind((host, port))

# Listen and set backlog (?)
s.listen(5)

# Process connections
print('Listening on port', port)
while True:
    c, addr = s.accept()
    print("Got connection from", addr)
    msg = "<html></html>"

    response_headers = {
        'Content-Type': 'text/html; encoding=utf8',
        'Content-Length': len(msg.encode(encoding="utf-8")),
        'Connection': 'close',
    }

    response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in response_headers.items())

    response_proto = 'HTTP/1.1'
    response_status = '200'
    response_status_text = 'OK' # this can be random

    # sending all this stuff
    r = '%s %s %s' % (response_proto, response_status, response_status_text)
    c.send(r.encode(encoding="utf-8"))
    c.send(response_headers_raw.encode(encoding="utf-8"))
    c.send('\n'.encode(encoding="utf-8")) # to separate headers from body
    c.send(msg.encode(encoding="utf-8"))

    c.close()
dopatraman
  • 13,416
  • 29
  • 90
  • 154

3 Answers3

1

The problem is that HTTP headers need to be line separated by \r\n not just \n. See RFC 1945 - HTTP/1.0 Sec 2.2 and RFC 7230 - HTTP/1.1 Syntax and Routing Sec 3.

If you change this it will fix the problem.

import socket

# Create socket object and set protocol
s = socket.socket(
    socket.AF_INET, socket.SOCK_STREAM)

# Get name of local machine
host = "127.0.0.1"
port = 8081

# Bind
s.bind((host, port))

# Listen and set backlog (?)
s.listen(5)

# Process connections
print('Listening on port', port)
while True:
    c, addr = s.accept()
    print("Got connection from", addr)
    msg = "<html><body><h1>This is a test</h1><p>More content here</p></body></html>"

    response_headers = {
        'Content-Type': 'text/html; encoding=utf8',
        'Content-Length': len(msg),
        'Connection': 'close',
    }

    response_headers_raw = ''.join('%s: %s\r\n' % (k, v) for k, v in response_headers.items())

    response_proto = 'HTTP/1.1'
    response_status = '200'
    response_status_text = 'OK' # this can be random

    # sending all this stuff
    r = '%s %s %s\r\n' % (response_proto, response_status, response_status_text)
    c.send(r)
    c.send(response_headers_raw)
    c.send('\r\n') # to separate headers from body
    c.send(msg.encode(encoding="utf-8"))

    c.close()
Community
  • 1
  • 1
drew010
  • 68,777
  • 11
  • 134
  • 162
  • My understanding is that CRLF `('\r\n')` is a windows-specific format. Will this work on a Unix system? – dopatraman Mar 22 '16 at 02:07
  • Also... this solution does not work. I'm able to receive a connection but cannot send a response to the browser. – dopatraman Mar 22 '16 at 02:10
  • Yes, CRLF is used by HTTP as an end-of-line marker (see [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3)). When I ran your code, I would get connection reset. When I changed to use `\r\n` between each header line, it works. Edited answer with full code. – drew010 Mar 22 '16 at 04:39
0

According to the ERR_CONNECTION_RESET error, chances are your tcp socket doesn't listen to the port successfully.

I change the port to 8080 in your code and write a Hello world in the output, resulting in getting the right HTML page.

If you want to listen to 80 port successfully, you have to use root user privilege to run your python script:

`sudo python server.py'

That is because 80 port is a system restricted port:Why are the first 1024 ports restricted to the root user only?.

Community
  • 1
  • 1
winiex
  • 125
  • 1
  • 8
  • If it wasn't listening `bind` would fail and the client would also get a connection refused, or eventually a timeout. But not a reset. That indicates it had connected at one point. – drew010 Mar 21 '16 at 03:27
  • Just to add onto @drew010, I'm able to hit the server running on port 80 via commandline. So connection on that port is not a problem. – dopatraman Mar 22 '16 at 02:20
-1

I assume that you will be able to listen to port 80 and accept connections because otherwise your server should throw an exception early.

My guess is you get the connection reset because your server does not read the clients request but instead simply sends some data and closes the connection - with the request from the client still in the socket buffer. This is such a typical error which was already asked and answered at Perl: Connection reset with simple HTTP server and HTTP Server Not Sending Complete File To WGET, Firefox. Connection reset by peer? and "The connection was reset" on web browsers when trying to connect to a localhost socket server and Ultra simple HTTP socket server, written in PHP, behaving unexpectedly and Simple http generic server using fork and dup.

Community
  • 1
  • 1
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • None of these links detail how to actually solve the problem. – dopatraman Mar 22 '16 at 02:24
  • @dopatraman: they all describe that the problem is that you don't read the request from the client but simply send a response and close the socket with the unread data. The solution is obviously to actually read the request from the client. Didn't you understand this correlation or don't you know how to read the request? – Steffen Ullrich Mar 22 '16 at 05:53