Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTTP POST contents in Haskell

I'm trying to post some data to a server in Haskell and the server side is coming up empty.

I'm using the Network.HTTP library for the request.

module Main (main) where

import Network.URI (URI (..), parseURI, uriScheme, uriPath, uriQuery, uriFragment)
import Network.HTTP
import Network.TCP as TCP

main = do
         conn <- TCP.openStream "localhost" 80
         rawResponse <- sendHTTP conn updateTest
         body <- getResponseBody rawResponse
         if body == rqBody updateTest
           then print "test passed"
           else print (body ++ " != " ++ (rqBody updateTest))

updateURI = case parseURI "http://localhost/test.php" of
                  Just u -> u

updateTest = Request { rqURI = updateURI :: URI
                     , rqMethod = POST :: RequestMethod
                     , rqHeaders = [ Header HdrContentType   "text/plain; charset=utf-8"
                                   ] :: [Header]
                     , rqBody = "Test string"
                     }

This test is returning the empty string as the response body from the server, when I think it should be echoing the "Test string" post.

I would ideally like to replicate the functionality of:

curl http://localhost/test.php -d 'Test string' -H 'Content-type:text/plain; charset=utf-8'

and am validating results with serverside test.php:

<?php
print (@file_get_contents('php://input'));

Am I doing this wrong or should I just be trying another library?

like image 781
Alex M Avatar asked Jun 20 '10 05:06

Alex M


2 Answers

You need to specify a Content-Length HTTP header, whose value must be the length of the raw posted data:

updateTest = Request { rqURI     = updateURI
                     , rqMethod  = POST
                     , rqHeaders = [ mkHeader HdrContentType "application/x-www-form-urlencoded"
                                   , mkHeader HdrContentLength "8"
                                   ]
                     , rqBody    = "raw data"
                     }
like image 106
Ionuț G. Stan Avatar answered Nov 15 '22 23:11

Ionuț G. Stan


And with http-conduit:

{-# LANGUAGE OverloadedStrings #-}

import Network.HTTP.Conduit
import qualified Data.ByteString.Lazy as L

main = do
  initReq <- parseUrl "http://localhost/test.php"

  let req = (flip urlEncodedBody) initReq $
             [ ("", "Test string")
--             ,
             ]

  response <- withManager $ httpLbs req

  L.putStr $ responseBody response

The "Test string", in the above example, is urlEncoded before being posted.

You can also set the method, content-type, and request body manually. The api is the same as in http-enumerator a good example is: https://stackoverflow.com/a/5614946

like image 45
Davorak Avatar answered Nov 16 '22 00:11

Davorak