I am trying to learn a little more about the operation of sockets and network connections in SBCL; so I wrote a simple wrapper for HTTP. Until now, it simply creates a stream and executes a request to ultimately get the header data and page content on the website.
Until now, he has worked pretty well. Nothing to brag about at home, but at least it worked.
I ran into some strange problem; I keep getting the "400 Bad Request" errors.
Firstly, I was a little cautious about how I processed HTTP requests (more or less passing the request string as an argument to the function), then I created a function that formats the request string with all the parts I need, and it returns for use later ... but I'm still getting errors.
What's even weirder is that errors do not occur every time. If I try a script on a page such as Google, I get a return value of "200 Ok" ... but at other times on other sites I get a "400 Bad Request".
I'm sure this is a problem with my code, but I will be damned if I know for sure what causes it.
Here is the code I'm working with:
(use-package :sb-bsd-sockets)
(defun read-buf-nonblock (buffer stream)
(let ((eof (gensym)))
(do ((i 0 (1+ i))
(c (read-char stream nil eof)
(read-char-no-hang stream nil eof)))
((or (>= i (length buffer)) (not c) (eq c eof)) i)
(setf (elt buffer i) c))))
(defun http-connect (host &optional (port 80))
"Create I/O stream to given host on a specified port"
(let ((socket (make-instance 'inet-socket
:type :stream
:protocol :tcp)))
(socket-connect
socket (car (host-ent-addresses (get-host-by-name host))) port)
(let ((stream (socket-make-stream socket
:input t
:output t
:buffering :none)))
stream)))
(defun http-request (stream request &optional (buffer 1024))
"Perform HTTP request on a specified stream"
(format stream "~a~%~%" request )
(let ((data (make-string buffer)))
(setf data (subseq data 0
(read-buf-nonblock data
stream)))
(princ data)
(> (length data) 0)))
(defun request (host request)
"formated HTTP request"
(format nil "~a HTTP/1.0 Host: ~a" request host))
(defun get-page (host &optional (request "GET /"))
"simple demo to get content of a page"
(let ((stream (http-connect host)))
(http-request stream (request host request)))
source
share