Server side includes (ssi) on IIS server, read POST request data fails - python

My Goal is that my SSI (shtml) will parse POST data parameters and return a long encrypted string which will be based on those parameters.
I am using IIS as the server.
My constraints:
I can't change the url - /document.shtml
The shtml need to return only the base 64 string result.
What i tried:
Use of "exec cgi" in the shtml, this way:
document.shtml:
<!--#exec cgi="/pythonApp/test.py?sdfsdf=sdfsdf" -->
test.py (simplified version , without the encryption logic behind):
import cgitb
cgitb.enable()
import base64,urllib,json,os,sys
import cgi
print "Content-Type: text/plain;charset=utf-8"
print
cl, _ = cgi.parse_header(os.environ['CONTENT_LENGTH'])
if (int(cl)>0):
data = sys.stdin.read(int(cl))
input_j = json.loads(data)
print "AB : ",input_j["AB"]
else:
print "Failed to read POST request"
The problem here, is that if i send post request to .../test.py , then it works,
but if i send the request to document.shtml, the content length will still be positive as described by the environment variable, but the stdin will get an error.
My other idea was to read the POST data , somehow from the shtml itself and pass it to the cgi , this way:
<!--#exec cgi="/pythonApp/test.py?sdfsdf=sdfsdf" -->
The problem , is that i looked over the net and haven't found a way to do it from the shtml.
Any suggestions? am i missing something simple?

I haven't found away to do it using SSI directive , i did understand that the stdin is not passed to the cgi from the main script.
So i found other solution which still answers my constrains.
In the IIS Handler Mapping for SHTML , i configured the executable to be php.
and in the shtml it self i wrote a php code (showing here just the sample that prints the json string):
<?php var_dump($HTTP_RAW_POST_DATA); ?>

Related

Updating records with Python 3 through API on Rails 4 application

I'm working on a Rails 4 / mongoid application which needs to expose APIs for other applications and scripts. I need to be able to update documents in one of the models through an API with Python 3 script. I'm a bit fresh with Python hence asking for help here.
I already found out how to query Rails APIs with Python 3 and urllib but struggling with updates. I was trying to go through Python 3.5 docs for urllib2 but struggling to apply this to my script.
What goes to data and how to add authentication token to headers, which in curl would look something like this
-H 'Authorization:Token token="xxxxxxxxxxxxxxxx"'
-X POST -d "name=A60E001&status=changed"
I would greatly appreciate if somebody explained how to, for example, update status based on name (name is not unique yet but will be). My biggest challenge is the Python side. Once I have the data in params on Rails side I think I can handle it. I think.
I included my model and update action from the controller below.
app/models/experiment.rb
class Experiment
include Mongoid::Document
include Mongoid::Timestamps
field :name, type: String
field :status, type:String
end
app/controllers/api/v1/experiments_controller.rb
module Api
module V1
class ExperimentsController < ActionController::Base
before_filter :restrict_access
...
def update
respond_to do |format|
if #expt_proc.update(expt_proc_params)
format.json { render :show, status: :ok, location: #expt_proc }
else
format.json { render json: #expt_proc.errors, status: :unprocessable_entity }
end
end
end
...
private
def restrict_access
authenticate_or_request_with_http_token do |token, options|
ApiKey.where(access_token: token).exists?
end
end
...
I figured out who to send a PATCH request with Python 3 and update the the record's status by name.
Thanks to this post found out about requests module. I used requests.patch to update the record and it works great.
python code
import requests
import json
url = 'http://0.0.0.0:3000/api/v1/update_expt_queue.json'
payload = {'expt_name' : 'myExperiment1', 'status' : 'finished' }
r = requests.patch(url, payload)
There are two problems remaining:
How to add headers to this request which would allow me to go through token based authentication. At the moment it's disabled. request.patch only takes 2 parameters, it doesn't take headers parameter.
How to access the JSON which is sent in response by Rails API.

Python cgi.FieldStorage() always returns a blank form, and can't read params from http POST

I'm attempting to get a basic Python webserver example going that receives data from a http POST. I'm currently using Postman to send the http POST as follows:
Here is my Python script:
# simple_web_server.py
import SimpleHTTPServer
import SocketServer
import cgi
###################################################################################################
def main():
myRequestHandler = MyRequestHandler
socketTCPServer = SocketServer.TCPServer(('0.0.0.0', 8080), myRequestHandler)
print 'starting server, use <Ctrl-C> to stop'
socketTCPServer.serve_forever()
###################################################################################################
class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
print "in do_GET(self)"
return SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self):
print "in do_POST(self)" # this shows successfully to the command line
form = cgi.FieldStorage()
print cgi.print_form(form) # this always prints an empty form
print str(form.getvalue('name')) # this always prints an empty string
if "name" not in form or "addr" not in form: # the if never runs
print "Please fill in the name and addr fields."
else:
print "<p>name:", form["name"].value
print "<p>addr:", form["addr"].value
self.wfile.write("test response 123 \n") # this shows successfully in Postman
self.send_response(200) # the 200 is successfully received by Postman
###################################################################################################
if __name__ == "__main__":
main()
Here are the command line results from Python when ran:
starting server, use <Ctrl-C> to stop
127.0.0.1 - - [05/Jul/2016 20:02:33] "POST /?param1=value1&param2=value2 HTTP/1.1" 200 -
in do_POST(self)
<H3>Form Contents:</H3>
<P>No form fields.
<DL>
</DL>
None
None
Please fill in the name and addr fields.
As far as I can tell from the python.org docs and every example I could find I'm doing everything correctly but the form data is always blank. Eventually I need to download a file sent by the POST but I'm going to hold off on that until I can read the form at all. Has anybody else ran into this? Any assistance would be greatly appreciated.
I could be wrong but I think if you're running a base server like this, then you access the POST data via:
content_length = int(self.headers['Content-Length']) # <--- Gets the size of data
post_data = self.rfile.read(content_length) # <--- Gets the data itself
If you wanted to access the POST data using
form = cgi.FieldStorage()
you would access that outside the base server class. So in the main method or something like that.

How do I pass event arguments to python scripts that run in response to Splunk alerts?

This is my script but it is not working as it is saying that sys.arg[8] is out of index range.
Splunk:
Your alert can trigger a shell script or batch file, which must be located in $SPLUNK_HOME/bin/scripts. Use the following attribute/value pairs:
action.script =
Splunk currently enables you to pass arguments to scripts both as command line arguments and as environment variables. This is because command line arguments don't always work with certain interfaces, such as Windows.
The values available in the environment are as follows:
SPLUNK_ARG_0 Script name
SPLUNK_ARG_1 Number of events returned
SPLUNK_ARG_2 Search terms
SPLUNK_ARG_3 Fully qualified query string
SPLUNK_ARG_4 Name of saved search
SPLUNK_ARG_5 Trigger reason (for example, "The number of events was greater than 1")
SPLUNK_ARG_6 Browser URL to view the saved search
SPLUNK_ARG_8 File in which the results for this search are stored (contains raw results)
SPLUNK_ARG_7 is not used for historical reasons.
These can be referenced in UNIX shell as $SPLUNK_ARG_0 and so on, or in Microsoft batch files via %SPLUNK_ARG_0% and so on. In other languages (perl, python, and so on), use the language native methods to access the environment.
#! /usr/bin/python
#Install requests package for python
import requests
import csv, gzip, sys
# Set the request parameters
url = 'https://xxxxxxxxdev.service-now.com/api/now/table/new_call'
user = 'xxxxx'
pwd = 'xxxxxx'
event_count = int(sys.argv[1]) # number of events returned.
results_file = sys.argv[8] # file with search results
# Set proper headers
headers = {"Content-Type":"application/json","Accept":"application/json"}
for row in csv.DictReader(openany(results_file)):
output="{"
for name,val in row.iteritems():
if output!="{":
output+=","
output += '"'+name+'":"'+val+'"'
output+="}"
# Do the HTTP request
response = requests.post(url, auth=(user, pwd), headers=headers, data='{"short_description":"Theo\'s Test for Splunk to SN","company":"company\'s domain","u_source":"Service Desk","contact_type":"Alert","description":"Please place detailed alert detail including recommended steps"}')
# Check for HTTP codes other than 200
if response.status_code != 201:
print('Status:', response.status_code, 'Headers:', response.headers, 'Error Response:',response.json())
exit()
# Decode the JSON response into a dictionary and use the data
#resp=response.json()
#print('Status:',response.status_code,'Headers:',response.headers,'Response:',re sponse.json())
print response.headers['location']
}
I see you are using the openany command, but haven't defined it in your code. Could that be causing the issue?
Otherwise, this should definitely be working, it matches my sample code and the code in the Splunk docs
import gzip
import csv
def openany(p):
if p.endswith(".gz"):
return gzip.open(p)
else:
return open(p)
results = sys.argv[8]
for row in csv.DictReader(openany(results)):
# do something with row["field"]

Unable to load google ajax components from the network...you can add &html to the url as a workaround

My python program contains 'n' times the below snippet of code.I only change the 'url' each time. When I run my python program I get separate output for each http request. These outputs are written into the file.
Some of the responses doesn't come up in the file.There is just blank where I expect the response for that particular http request. However If I were to take the code snippet for http request that fails to a separate py file that does works as expected. I call fp.flush() after every single write in my python program. I can't figure out what else might be going wrong.It would be great If anyone can point it out. If I view the output html file in text format, in the section where the URL failed, I get the following error message.
'Unable to load google ajax components from the network...you can add
&html to the url as a workaround...'
Can someone point out to me what is wrong here.?
fp = open("output.html","wb")
url='https://localhost:9006/opexxxons?metxxcs'
r = requests.get(url,auth=('admin','admin'),verify=False)
if True:
fp.write('<br><br>')
fp.write('<b>' + url + '</b>' + '<br>')
fp.write('<br><br>')
fp.write(r.text)
fp.flush()
else:
fp.write(url + 'Failed')

how to make json request in haskell using wreq?

I have a server which accepts json requests and they work fine with python client. I am trying to do the same thing in haskell.
For instance my python client has following code
conn = JSONRPCProxy("XXX.XX.XX.XX", 5050, "2.0", 120)
print conn.request('show_attrs', [{"shortcode":"CODEWORD1","fx":'CD2'}, ["?queryattr", "queryname"]]);
I want to send out the same query using haskell and get json back as result. Not worried about json parsing as of now!
I tried Network.Wreq and it kinda works but always gives no response
data MyPriceRequest = MyRequestRequest { method::String,id::Int} deriving (Show,Generic)
instance ToJSON MyPriceRequest
r <- post "http://IP.IP.IP.IP:port/" (toJSON (MyRequestRequest "codeword" [""] 1))
*** Exception: NoResponseDataReceived
I get exception but same code works with python
In python it works with...
conn = JSONRPCProxy("IP.IP.IP.IP", port, "2.0", 120)
print conn.request('codeword', []);
Here's a working example doing a POST query on httpbin.org:
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Network.Wreq
import Control.Lens
import Data.Aeson.Lens
import qualified Data.Text as T
import Data.Aeson
main = do
r <- post "http://httpbin.org/post" (toJSON (T.unpack "123"))
let datas = r ^. responseBody . key "data" . _String
ua = r ^. responseBody . key "headers" . key "User-Agent" . _String
(putStrLn . T.unpack) datas
(putStrLn . T.unpack) ua
It should print something like:
"123"
haskell wreq-0.3.0.1
I tried it with URLs of the form http://127.0.0.1:80 and it gave the same result.
Have you tried to use curl in your shell to see if it exhibits the same behavior ?
Is it possible that the server answers only if some header fields are present or set at a specific value ?

Categories