title: In a Python3 CGI script, how can I read the raw form data in a POST?
body: <p>Yes, I'm aware of <code>cgi.FieldStorage</code>, but, being some form of unordered dictionary, <strong>it does not preserve the order</strong> of the original data (see below for proof).  Since I wish to use this data with PayPal IPN, order is important <a href="https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/" rel="noreferrer">PayPal docs here</a>, which say "...you must send back the contents in the exact order they were received..."</p>
  
  <p>Alternatively, <code>os.environ.get('QUERY_STRING')</code> looks perfect, however, <strong>it seems to only work for a GET</strong>.  Example code: (myscript.py)</p>
  
  <pre><code>#!/usr/bin/python3
  
  import cgi, os
  
  query = os.environ.get('QUERY_STRING') or 'no query'
  print ("Content-type: text/plain\n\n")
  print("query=" + query)
  form = cgi.FieldStorage()
  for key in form.keys():
     print("\n" + key + '=' + form.getvalue(key))
  </code></pre>
  
  <p>Works with a GET from the browser, e.g. (note that foo is <em>before</em> ggg) </p>
  
  <pre><code>http://example.com/myscript.py/foo=bar&amp;ggg=3&amp;aaa=bbb&amp;zzz=qqq
  </code></pre>
  
  <p>returns</p>
  
  <pre><code>query=foo=bar&amp;ggg=3&amp;aaa=bbb&amp;zzz=qqq
  ggg=3
  foo=bar   &lt;&lt; note that foo now comes after ggg
  aaa=bbb
  zzz=qqq
  </code></pre>
  
  <p>However, if I use Postman to POST</p>
  
  <pre><code>POST /myscript.py HTTP/1.1
  Host: example.com
  Cache-Control: no-cache
  Content-Type: application/x-www-form-urlencoded
  
  foo=bar&amp;ggg=3&amp;aaa=bbb&amp;zzz=qqq
  </code></pre>
  
  <p>It returns no query string, and, as expected, the FormData did not preserve the order.</p>
  
  <pre><code>query=no query
  ggg=3
  foo=bar   &lt;&lt; note that foo now comes after ggg
  aaa=bbb
  zzz=qqq
  </code></pre>