cgi URL forwarding with "Location" header - only partial forwarding? - python

Greetings all,
I have a python CGI script which using
print "Location: [nextfilename]"
print
After "forwarding" (the reason for the quotes there is apparent in a second), I see the HTML of the page to which it has forwarded fine, but all images, etc. are not showing. The address bar still shows the cgi script as the current location, not the HTML file itself. If I go to the HTML file directly, it displays fine.
Basically, the CGI script, which is stored in the cgi-bin, whereas the HTML files are not, is trying to render images with relational links that are broken.
How do I actually forward to the next page, not just render the next page through the cgi script?
I have gone through the script with a fine-toothed comb to make sure that i wasn't actually using a print htmlDoc command anywhere that would be interrupting and screwing this up.
Sections of Code that are Applicable:
def get_nextStepName():
"""Generates a random filename."""
nextStepBuilder = ["../htdocs/bcc/"]
fileLength = random.randrange(10)+5
for i in range(fileLength):
j = random.choice(varLists.ALPHANUM)
nextStepBuilder.append(j)
nextStepName = ""
for char in nextStepBuilder:
nextStepName += char
nextStepName += ".html"
return nextStepName
def make_step2(user, password, email, headerContent, mainContent, sideSetup, sideContent, footerContent):
"""Creates the next step of user registration and logs valid data to a pickle for later confirmation."""
nextStepName = get_nextStepName()
mainContent = "<h1>Step Two: The Nitty Gritty</h1>"
mainContent += "<p>User Name: %s </p>" % (user)
mainContent += """\
[HTML CODE GOES HERE]
"""
htmlDoc = htmlGlue.glue(headerContent, mainContent, sideSetup, sideContent, footerContent)
f = open(nextStepName, "w")
f.write(htmlDoc)
f.close()
nextStepName = nextStepName[9:] #truncates the ../htdocs part of the filename to fix a relational link issue when redirecting
gotoNext(nextStepName)
def gotoNext(filename):
nextLocation = "Location:"
nextLocation += filename
print(nextLocation)
print
Any thoughts? Thanks a ton. CGI is new to me.

You need to send a 30X Status header as well. See RFC 2616 for details.

Related

How can I change inline styling in a local html file from a Python script?

I am working to make a status page of sorts. Essentially, it will be a basic HTML page with a little CSS that displays a list of servers and a green bubble for online, red for offline. I have the page looking the way I want and my script to ping all the servers works. I achieved the bubbles by using a very simple span tag, then setting background-color to limegreen.
The Python script iterates through a list of servers and pings each one four times. Afterwards, it checks the result and prints a message to show whether or not the server is online.
The problem I have is that I can't get the two to work together. How can I use Python and BeautifulSoup to go into my HTML file and modify the style of an element based on the result of a ping?
Example: Server 1 is online and the circle is green. Server 2 goes down, the script notices a bad ping. Script then navigates to HTML and changes the span background-color for server 2 to red.
Here is the code for the python script:
# import dependencies
import os
import pandas
from bs4 import BeautifulSoup
import re
soup = BeautifulSoup(open('index.html'), 'html.parser')
# import servernames from csv, convert to list
colnames = ['SERVERNAME']
data = pandas.read_csv('Server_List.csv', names=colnames)
hostnames = data.SERVERNAME[1:].tolist()
# ping each server
for hostname in hostnames:
# pings each server four times
response = os.system("ping -n 4 " + hostname)
head, sep, tail = hostname.partition('.')
# check the response
if response == 0:
print('\n', flush=True)
print(head.upper(), 'is up!\n', flush=True)
else:
print('\n', flush=True)
print(head.upper(), 'is down!\n', flush=True)
Here is one of my spans:
<span class="status" style="background-color: limegreen;">
And here is my class:
.status {
padding: 2px 11px;
border-radius: 100%;
}
You'll need to generate HTML dynamically.
This can be done using a template engine, but you can also do it "manually".
This is an example on how it could work:
import os
import pandas
import re
import html
# Define the template string. Could also be loaded from a file
template = """<html>
<head>
</head>
<body>
Server Status:
$$replace_this$$
</body>
</html>"""
# import servernames from csv, convert to list
colnames = ['SERVERNAME']
data = pandas.read_csv('Server_List.csv', names=colnames)
hostnames = data.SERVERNAME[1:].tolist()
html_input = ""
# ping each server
for hostname in hostnames:
# ping server four times
response = os.system("ping -n 4 " + hostname)
head, sep, tail = hostname.partition('.')
# Append server name, escape server name to prevent injection attacks (in case data contains malicious content)
html_input += "<p>" + html.escape(hostname)
# check the response
if response == 0:
html_input += "Server is <b>up</b>"
else:
html_input += "Server is <b>down</b>"
html_input += "</p>\n"
html_result = template.replace("$$replace_this$$", html_input)
# Now you can use html_result for anything, such as writing it to a file.
Note that this is not the most efficient or professional method, but it probably works well enough.

Flask - render page without return

I'm working on an application, where user fills in form.
One of the fields asks for postcode. When request is sent, a separate thread runs python code using PYQT5, rendering page and scraping web, (don't want to pay for API from google) providing mileage between given postcode and set postcode. Results of this thread are saved in a file.
What i would like to do is to open a new webpage with information that the data is being checked. This page would run python code, which checks for results in a file (that takes up to few seconds) using while loop. if the result is in the file, the page redirect to another page.
Is there a way to render a page (or redirect to another page) without using RETURN? i understand that when I use return render_templates (page), rest of the code is ignored.
#app.route('/add_user', methods=['GET', 'POST'])
def add_user():
file = open('app/results_from_g.txt','w')
file.write('')
file.close()
form = AddForm()
if form.validate_on_submit():
url = 'https://google.co.uk/maps/dir/...'
def sendtogoogle(url):
os.system('python googlemaps_mileage.py ' +url)
thread1=threading.Thread(target=sendtogoogle, args=(url,))
thread1.start()
the next line of the code should be redirect to another page, and when results are in the file, either back here, or different page:
while result_from_file==0:
file = open('results_from_g.txt','r')
result_from_file = file.read()
if result_from_file =='': #means no data saved in the file yet
time.sleep(1)
elif wynik =='0': #means wrong postcode
//render page 'wrong postcode'
else:
//render page 'correct postcode

How do i understand whether i am parsing the websites acurately?

I built this function to tell me whether there have been changes to the website. I'm not sure if it works as I have tried it on a few websites that have not changed and it has given me the wrong output. Where is the issue and is there an issue at all?
This is the code:
I put the code into a function so that I could allow the user to input any site
userurl=input("Please enter a valid url")
def checksite(userurl):
change=False
import time
import urllib.request
import io
u = urllib.request.urlopen(userurl)
webContent1 = u.read()
time.sleep(60)
u = urllib.request.urlopen(userurl)
webContent2 = u.read()
if webContent1 == webContent2:
print("Everything is normal")
elif webContent1 !=webContent2:
print("Warning, there has been a change to the webite!")
change=True
return change
checksite(userurl)
Try making a small HTML Hello World page. Given that many websites have dynamic content that changes each time you access it (and might not necessarily be visible), that could lead to your "incorrect" results.
I have tested your code and it works perfectly fine in a Python webserver.
I have started one with
python -m http.server
and placed an index.html in the same directory with some content before starting the server.
and your code
import time
import urllib.request
import io
userurl='http://localhost:8000/index.html'
def checksite(userurl):
change=False
u = urllib.request.urlopen(userurl)
webContent1 = u.read()
print(webContent1)
time.sleep(15)
u = urllib.request.urlopen(userurl)
webContent2 = u.read()
print(webContent2)
if webContent1 == webContent2:
print("Everything is normal")
elif webContent1 !=webContent2:
print("Warning, there has been a change to the webite!")
change=True
return change
checksite(userurl)
and output
b'<html>\n\t<title> Hello </title>\n\t<body>\n\t\tTesting, Webcontent1 \n\t</body>\n\t</html>\n\n'
b'<html>\n\t<title> Hello </title>\n\t<body>\n\t\tTesting, Webcontent2\n\t</body>\n\t</html>\n\n'
Warning, there has been a change to the webite!
[Finished in 17.5s]
Your code is perfectly fine.
to know if a website or a page has changed you need to have a backup of it somewhere, in your code it was like you were comparing the site to itself... anyways. i recomend using the requests library in addition to BS4 and try parsing it line by line comparing to the backup you have.
So while the code is working (aka: the site you have as backup is showing the same lines as the site on the web) it will have a variable true. if it has changed it breaks the loop and simply shows the line where the site has changed.

MySQL connection/query make file not work

I've got some test code I'm working on. In a separate HTML file, a button onclick event gets the URL of the page and passes it as a variable (jquery_input) to this python script. Python then scrapes the URL and identifies two pieces of data, which it then formats and concatenates together (resulting in the variable lowerCaseJoined). This concatenated variable has a corresponding entry in a MySQL database. With each entry in the db, there is an associated .gif file.
From here, what I'm trying to do is open a connection to the MySQL server and query the concatenated variable against the db to get the associated .gif file.
Once this has been accomplished, I want to print the .gif file as an alert on the webpage.
If I take out the db section of the code (connection, querying), the code runs just fine. Also, I am successfully able to execute the db part of the code independently through the Python shell. However, when the entire code resides in one file, nothing happens when I click the button. I've systematically removed the lines of code related to the db connection, and my code begins stalling out at the first line (db = MySQLdb.connection...). So it looks like as soon as I start trying to connect to the db, the program goes kaput.
Here is the code:
#!/usr/bin/python
from bs4 import BeautifulSoup as Soup
import urllib
import re
import cgi, cgitb
import MySQLdb
cgitb.enable() # for troubleshooting
# the cgi library gets the var from the .html file
form = cgi.FieldStorage()
jquery_input = form.getvalue("stuff_for_python", "nothing sent")
# the next section scrapes the URL,
# finds the call no and location,
# formats them, and concatenates them
content = urllib.urlopen(jquery_input).read()
soup = Soup(content)
extracted = soup.find_all("tr", {"class": "bibItemsEntry"})
cleaned = str(extracted)
start = cleaned.find('browse') +8
end = cleaned.find('</a>', start)
callNo = cleaned[start:end]
noSpacesCallNo = callNo.replace(' ', '')
noSpacesCallNo2 = noSpacesCallNo.replace('.', '')
startLoc = cleaned.find('field 1') + 13
endLoc = cleaned.find('</td>', startLoc)
location = cleaned[startLoc:endLoc]
noSpacesLoc = location.replace(' ', '')
joined = (noSpacesCallNo2+noSpacesLoc)
lowerCaseJoined = joined.lower()
# the next section establishes a connection
# with the mySQL db and queries it
# using the call/loc code (lowerCaseJoined)
db = MySQLdb.connect(host="localhost", user="...", "passwd="...",
db="locations")
cur = db.cursor()
queryDb = """
SELECT URL FROM locations WHERE location = %s
"""
cur.execute(queryDb, lowerCaseJoined)
result = cur.fetchall()
cur.close()
db.close()
# the next 2 'print' statements are important for web
print "Content-type: text/html"
print
print result
Any ideas what I'm doing wrong?
I'm new at programming, so I'm sure there's a lot that can be improved upon here. But prior to refining it I just want to get the thing to work!
I figured out the problem. Seems that I had quotation mark before the password portion of the db connection line. Things are all good now.

Python newbie - Input strings, return a value to a web page

I've got a program I would like to use to input a password and one or multiple strings from a web page. The program takes the strings and outputs them to a time-datestamped text file, but only if the password matches the set MD5 hash.
The problems I'm having here are that
I don't know how to get this code on the web. I have a server, but is it as easy as throwing pytext.py onto my server?
I don't know how to write a form for the input to this script and how to get the HTML to work with this program. If possible, it would be nice to make it a multi-line input box... but it's not necessary.
I want to return a value to a web page to let the user know if the password authenticated successfully or failed.
dtest
import sys
import time
import getopt
import hashlib
h = hashlib.new('md5')
var = sys.argv[1]
print "Password: ", var
h.update(var)
print h.hexdigest()
trial = h.hexdigest()
check = "86fe2288ac154c500983a8b89dbcf288"
if trial == check:
print "Password success"
time_stamp = time.strftime('%Y-%m-%d_%H-%M-%S', (time.localtime(time.time())))
strFile = "txt_" + str(time_stamp) + ".txt"
print "File created: txt_" + str(time_stamp) + ".txt"
#print 'The command line arguments are:'
#for i in sys.argv:
#print i
text_file = open(strFile, "w")
text_file.write(str(time_stamp) + "\n")
for i in range(2, len(sys.argv)):
text_file.write(sys.argv[i] + "\n")
#print 'Debug to file:', sys.argv[i]
text_file.close()
else:
print "Password failure"
You'll need to read up on mod_python (if you're using Apache) and the Python CGI module.
Take a look at django. It's an excellent web framework that can accomplish exactly what you are asking. It also has an authentication module that handles password hashing and logins for you.

Categories