0

I am having a device which is sending the following http message to my RaspberryPi:

POST /sinvertwebmonitor/InverterService/InverterService.asmx/CollectInverterData HTTP/1.1
Host: www.automation.siemens.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 349

xmlData=<rd><m>xxxxx</m><s>yyyyyy</s><d t="1483019400" l="600"><p i="1">460380AE</p><p i="2">43655DE7</p><p i="3">4212C986</p><p i="4">424805BC</p><p i="5">4604E3D1</p><p i="6">441F616A</p><p i="7">4155E7F5</p><p i="8">E1</p><p i="9">112</p><p i="C">153</p><p i="D">4</p><p i="E">11ABAC</p><p i="F">22A48C</p><p i="10">0</p></d></rd>

I cannot change anything on the device.

On the RaspberryPi im running a script to listen and receive the message from a socket. This works so far and the received message is the one above.

Now, I would like to create a HTTP object from this message and then extract comfortably the header, content and so on. Similar to the following example:

r = requests.get('https://www.google.com')
r.status_code

However, without "getting" an url. I just want to read the string I already have.

Pseudo-example:

r = requests.read(hereComesTheString)
r.status_code

I hope the problem became understandable.

Would be glad to get some hints.

Thanks and best regards, Christoph

cmolitor
  • 156
  • 1
  • 7
  • 2
    If this is all local/serverless, why would you care what the headers or status code are? Wouldn't you just care about the contents of the string? I'm trying to figure out what your real use case it. – wkl Dec 30 '16 at 16:25
  • You mean, from your RPi, you want to dissect the HTTP request and make an HTTP response? Does your socket server already implement HTTP? – Alastair McCormack Dec 30 '16 at 16:27
  • Possible duplicate of [python parse http response (string)](http://stackoverflow.com/questions/24728088/python-parse-http-response-string) – martianwars Dec 30 '16 at 16:29
  • @birryree: I would like to change for example the path and pass the message on. I know that I can do that with some parsing and replacing but I thought there might be a more elegant way.. – cmolitor Dec 30 '16 at 20:05
  • It definitely sounds like what you want is to set up server or proxy on your RPi, then. I think Alistair McCormack's answer may be heading in the right direction for your need. – wkl Dec 30 '16 at 20:07

3 Answers3

0

If you're using plain socket server, then you need to implement an HTTP server so that you can split the request and respond according to the protocol.

It's probably easier just to use an existing HTTP server and app server. Flask is ideal for this:

from flask import Flask
from flask import request

app = Flask(__name__)

@app.route("/sinvertwebmonitor/InverterService/InverterService.asmx/CollectInverterData", methods=['POST'])
def dataCollector():
    data = request.form['xmlData']
    print(data)
    # parseData. Take a look at ElementTree

if __name__ == "__main__":
    app.run(host=0.0.0.0, port=80)
Alastair McCormack
  • 26,573
  • 8
  • 77
  • 100
0

You use the status_code property in your example, but what you are receiving is a request not a response. However you can still create a simple object for accessing the data in the request.

It is probably easiest to create your own custom class:

import mimetools
from StringIO import StringIO

request = """POST /sinvertwebmonitor/InverterService/InverterService.asmx/CollectInverterData HTTP/1.1
Host: www.automation.siemens.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 349

xmlData=<rd><m>xxxxx</m><s>yyyyyy</s><d t="1483019400" l="600"><p i="1">460380AE</p><p i="2">43655DE7</p><p i="3">4212C986</p><p i="4">424805BC</p><p i="5">4604E3D1</p><p i="6">441F616A</p><p i="7">4155E7F5</p><p i="8">E1</p><p i="9">112</p><p i="C">153</p><p i="D">4</p><p i="E">11ABAC</p><p i="F">22A48C</p><p i="10">0</p></d></rd>"""

class Request:
    def __init__(self, request):
        stream = StringIO(request)
        request = stream.readline()

        words = request.split()
        [self.command, self.path, self.version] = words

        self.headers = mimetools.Message(stream, 0)
        self.content = stream.read()

    def __getitem__(self, key):
        return self.headers.get(key, '')

r = Request(request)
print(r.command)
print(r.path)
print(r.version)

for header in r.headers:
    print(header, r[header])

print(r.content)

This outputs:

POST
/sinvertwebmonitor/InverterService/InverterService.asmx/CollectInverterData
HTTP/1.1
('host', 'www.automation.siemens.com')
('content-type', 'application/x-www-form-urlencoded')
('content-length', '349')
xmlData=<rd><m>xxxxx</m><s>yyyyyy</s><d t="1483019400" l="600"><p i="1">460380AE</p><p i="2">43655DE7</p><p i="3">4212C986</p><p i="4">424805BC</p><p i="5">4604E3D1</p><p i="6">441F616A</p><p i="7">4155E7F5</p><p i="8">E1</p><p i="9">112</p><p i="C">153</p><p i="D">4</p><p i="E">11ABAC</p><p i="F">22A48C</p><p i="10">0</p></d></rd>
Alden
  • 2,229
  • 1
  • 15
  • 21
0

Thanks Alden. Below your code with a few changes so it works with Python3.

import email
from io import StringIO

request = """POST /sinvertwebmonitor/InverterService/InverterService.asmx/CollectInverterData HTTP/1.1
Host: www.automation.siemens.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 349

xmlData=<rd><m>xxxxx</m><s>yyyyyy</s><d t="1483019400" l="600"><p i="1">460380AE</p><p i="2">43655DE7</p><p i="3">4212C986</p><p i="4">424805BC</p><p i="5">4604E3D1</p><p i="6">441F616A</p><p i="7">4155E7F5</p><p i="8">E1</p><p i="9">112</p><p i="C">153</p><p i="D">4</p><p i="E">11ABAC</p><p i="F">22A48C</p><p i="10">0</p></d></rd>"""

class Request:
    def __init__(self, request):
        stream = StringIO(request)
        request = stream.readline()

        words = request.split()
        [self.command, self.path, self.version] = words

        self.headers = email.message_from_string(request)
        self.content = stream.read()

    def __getitem__(self, key):
        return self.headers.get(key, '')

r = Request(request)
print(r.command)
print(r.path)
print(r.version)

for header in r.headers:
    print(header, r[header])

print(r.content)
cmolitor
  • 156
  • 1
  • 7