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

5
  • 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. Commented Dec 30, 2016 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? Commented Dec 30, 2016 at 16:27
  • Possible duplicate of python parse http response (string) Commented Dec 30, 2016 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.. Commented Dec 30, 2016 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. Commented Dec 30, 2016 at 20:07

3 Answers 3

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>
Sign up to request clarification or add additional context in comments.

Comments

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)

1 Comment

Looks interesting and I will test it tomorrow as the device is offline now.
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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.