Server side call to webservice in classic ASP - asp.net

I've .NET webservice, which takes a encoded html-string as a parameter, decodes the string and creates a PDF from the html. I want to make a synchronous server side call to the webservice from a classic asp webpage. It works fine if use a plain text string (with no html tags), but when I send a encoded html string the webservice it seems that the string is empty when it reaches the webservice.
The webservice is working fine when I call it from client side, with both plain text string and an encoded html string.
My code looks like this:
Private Sub SaveBookHtmlToPdf(pHtml, pShopId)
Set oXMLHTTP = CreateObject("Msxml2.ServerXMLHTTP.6.0")
Dim strEnvelope
strEnvelope = "pShopId=" & pShopId & "&pEncodedHtml=" & Server.HTMLEncode(pHtml)
Call oXMLHTTP.Open("POST", "https://mydomain.dk:4430/PdfWebservice.asmx/SaveBookToPdf", false)
Call oXMLHTTP.SetRequestHeader("Content-Type","application/x-www-form-urlencoded")
Call oXMLHTTP.Send(strEnvelope)
Set oXMLHTTP = Nothing
End Sub
It smells like some kind of security issue on the server. It's working when posting a asynchronous call from the client side, but not when it comes from server side - it seems that the encoded html string is somehow not allowed in a server side call to the webservice.
Anyone who know how to solve this tricky problem?

This looks all wrong to me:
Server.HTMLEncode(pHtml)
Its quite common for developers to get confused between HTML encoding and URL encoding even though they are quite different. You are posting data that needs to be URL encoded. Hence your code should use URLEncode instead:
strEnvelope = "pShopId=" & pShopId & "&pEncodedHtml=" & Server.URLEncode(pHtml)
Edit:
One thing that URLEncode does that may not be compatible with a URLEncoded post is it converts space to "+" instead of "%20". Hence a more robust approach might be:
strEnvelope = "pShopId=" & pShopId & "&pEncodedHtml=" & Replace(Server.URLEncode(pHtml), "+", "%20")
Another issue to watch out for is that the current value of Response.CodePage will influence how the URLEncode encodes non-ASCII characters. Typically .NET does things by default in UTF-8. Hence you will also want to make sure that your Response.CodePage is set to 65001.
Response.CodePage = 65001
strEnvelope = "pShopId=" & pShopId & "&pEncodedHtml=" & Replace(Server.URLEncode(pHtml), "+", "%20")

This may or may not help but I use a handy SOAP Class for Classic ASP which solved a few problems I was having doing it manually. Your code would be something like this:
Set cSOAP = new SOAP
cSOAP.SOAP_StartRequest "https://mydomain.dk:4430/PdfWebservice.asmx", "", "SaveBookToPdf"
cSOAP.SOAP_AddParameter "pShopId", pShopId
cSOAP.SOAP_AddParameter "pEncodedHtml", Server.HTMLEncode(pHtml)
cSOAP.SOAP_SendRequest
' result = cSOAP.SOAP_GetResult("result")
You will probably need to set your namespace for it to work ("" currently), and uncomment the 'on error resume next' lines from the class to show errors.

AnthonyWJones made the point about URL encoding and HTML encoding, and the original problem being experienced is likely a combine of the two, a race condition if you will. While is was considered answered, it partially wasn't, and hopefully this answers the cause of the effect.
So, as the message get HTMLEncoded, the html entities for the tags become such '<' = '<'.
And as you may know, in URLEncoding, &'s delimit parameters; thus the first part of this data strEnvelope = "pShopId=" & pShopId & "&pEncodedHtml=" & Server.HTMLEncode(pHtml) upto the "&pEncodedHtml" bit, is fine. But then "<HTML>..." is added as the message, with unencoded &'s...and the receiving server likely is delimiting on them and basically truncating "&pEncodedHtml=" as a null assign: "&pEncodedHtml=<HTML>... ." The delimiting would be done on all &'s found in the URL.
So, as far as the server is concerned, the data for parameter &pEncodedHtml was null, and following it were now several other parameters that were considered cruft, that it likely ignored, which just happened to actually be your message.
Hope this provides additional info on issues of its like, and how to correct.

Related

Handling Chinese in ASP classic

I write the following piece of codes :
rst.Open(strSQL & Request.QueryString("C-PLACE")), conn, 0, 1
But got the following error. However, if the querystring is in English or just number, no error will pop out. Any guru can help please ?
Microsoft OLE DB Provider for ODBC Drivers error '80040e10'
[Microsoft][ODBC Microsoft Access Driver] Too few parameters. Expected 2.
/deliverable/GetMemberTest.asp, line 19
It's going to either be passing an encoding variable to the server, or in the case of your error, its saying "too few parameters". In this case, the parameter is "C-PLACE" and its suppose to be passed to your asp script from the previous page's link, something like:
/deliverable/GetMemberTest.asp?C-PLACE=THECPLACE
https://www.w3schools.com/asp/coll_querystring.asp
(citation about query strings)
or something like that .. obviously its not actually "THECPLACE", but just saying a QueryString("VARIABLENAME") looks to the URL of the previous page to pass the parameter to the script, so that error message should of done something to add a ? mark = C-PLACE= to something, and we aren't seeing that. So something on the previous page that was suppose to add this when they click a submit button didn't do it's job, or the script is just getting run on its own without the proper previous page's work being done to prepare it to execute properly on the following page.
It will also be of note that these types of things are easily hacked through sql script injection, so if you aren't validating your url first, someone could use some code to escape out of your sql and add their own code, such as one to drop your tables ..., so make sure you validate the variable FIRST instead of dumping it straight into your code. I can give some guidance into that later, but first lets figure out your problem.
(side note - can i request strSQL from you? Can you put this line in before that line:
<%
response.write("strSQL is " & StrSQL & "<BR>")
%>
All this code does is display what is stored in the StrSQL variable, see if we can figure out what is going on here. Also take note that your error message indicated that it expected 2 parameters, so we are missing 2 for this script to run properly.
EDIT - try this encoding:
<%
Response.CodePage=65001
Response.Charset="UTF-8"
Response.ContentType = "text/html"
%>
Try this strSQL, you didn't need the Response.Write and on C-PLACE you want to use '' instead of "" because the "" will exit you out of the SQL statement. Try this, and let me know how it works, but I still think we are going to need another parameter supplied to it, unless its getting one from the string and then it isn't actually counting the one supplied from the url perhaps.
<%
strSQL="SELECT * FROM DetailMemberInfo
WHERE C-PLACE=" & strSQL & Request.QueryString('C-PLACE'))"
%>

Classic ASP's Request.Form is dropping an 8-bit character -- is there a simple way to prevent this?

A client of mine is using a Classic ASP script to process a form from a third-party payment processor (this is the last step in a credit-card-transaction sequence that starts at the client's website, goes to the third-party site, and then returns to the client's site).
The client is in Austria and when one of the fields includes an 8-bit character (e.g., when the field value is Österreich), the Ö is simply dropped when I retrieve the value of the field in the standard way; e.g.:
fieldval = Request.Form("country")
If fieldval = "sterreich" Then
' Code here will execute
End If
The literal value that the third-party page is POSTing is %D6sterreich, which I think suggests that the POST is being encoded in UTF-8.
The POST request has the following possibly-relevant headers:
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Content-Type: application/x-www-form-urlencoded
I'm by no means a character-encoding expert and this is the first time I've really done anything with Classic ASP, so I'm kind of flummoxed.
From some Googling and searching SO, I've added the following to the page that processes the POST:
<%# Codepage=65001 %>
<%
Response.CharSet = "UTF-8"
Response.Codepage = 65001
%>
But it doesn't make any difference -- I still lose that initial 8-bit character. Is there something really simple that I'm just not aware of?
Try adding the following to the top of the page:
<%
Response.CharSet = "utf-8"
Session.CodePage = 65001
%>
Turns out I was going the wrong direction with this. The ASP file in question was itself encoded in UTF-8, which was implicitly setting Response.CodePage to 65001 -- in other words, explicitly adding a CODEPAGE directive made no difference -- and in fact the UTF-8 encoding was the source of the problem.
When I re-encoded the file to Windows-1252, the problem disappeared. I'm pretty ignorant of character encodings in general, but I think in retrospect the %D6 in the POST should have been my clue -- if I'm starting to understand things rightly, the single byte 0xD6 is not a valid UTF-8 character. Maybe someone more familiar with these things could confirm or deny this.
What about using the Ascii Character 0 in the query string, encoded as (%00), can I retrieve the whole value without terminating by Ascii 0?
http://localhost/Test_Authentication.asp?token=%13%23%02%00%01%01%00%01%01%05%02%02%03%00%02%02%0A%0A%0A%0A%0A%0A048
Response.CharSet = "utf-8";
Session.CodePage=65001;
var strToken = (Request.QueryString("token").Count > 0)?Request.QueryString("token")(1):"";
#Ben Dunlap: Try this at the top of the page --
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
Update
If you do a Response.Write Request.Form("country"), what does it display?
The 2 simple steps I used were:
add at the top of EVERY asp file:
Response.CharSet = "utf-8"
Response.CodePage = 65001
save every ASP text file in "ANSI" encoding (NOT utf-8!) - this option is usually found in the "Save" window of advanced text editors
If you save in utf-8 encoding or if you don't add the two line specified at the top of your code, this will never work as you intended.
My issue was similar (but quite strange) and adding the following two lines on all my pages has corrected it. Thanks so much for this.
Response.CharSet = "UTF-8"
Response.Codepage = 65001
But, to explain, here is the exact issue I had. Folks were entering Spanish characters on my ASP entry page and the results were very weird. For example" "Peña" was entered. The ASP page would display this, as entered, but what ended up in the database was displayed back as "Pe?a". This would have been sort of ok, except the hex actually stored in the database was 0x50653F6100. Notice the extra "00". Somehow the database stored value had an extra NULL at the end. So, when I later retrieved the data the screens went a little bonkers when the "00" [null] was hit and the displayed data essentially stopped after this data.
In any case adding the two lines seems to have fixed the issue and the "ñ" is stored in the database as it should be.

having trouble reading header values in classic ASP

This is all internal servers and software, so I'm very limited on my options, but this is where I'm at. This is already a band-aid to a workaround but I have no choice, so I'm just trying to make it work.
I have a simple .asp file on my server that is protected by a service that will handle the user authentication (I have no control over this service). When a user goes to this .asp file, it requires them to authenticate via the service, and the service then redirects them to the .asp.
The service is inserting custom values in to the http header that allow me to identify who has logged in (I need it further down the line). When I use the asp to view the ALL_RAW and ALL_HTTP values from the header, I can see all the custom values. But when I try to call these values specifically I get nothing.
I ran this simple loop:
<%
for each x in Request.ServerVariables
response.write("<B>" & x & ":</b> " & Request.ServerVariables(x) & "<p />")
next
%>
and all the keys display including the custom ones. But none of the custom values will. The values are the part I need.
the only thing I can find unique about the custom values is that they look slightly different in the ALL_RAW value, but they all look correct in the ALL_HTTP. As best I can tell, they are formatted correctly. the only formatting differences between the standard and custom values are case and underscores instead of hyphens.
Why can I not read these custom values?
I found my answer.
When I ran this loop
<%
for each x in Request.ServerVariables
response.write("<B>" & x & ":</b> " & Request.ServerVariables(x) & "<p />")
next
%>
it would return a list of all the names that were in the header and their values. The custom value I was looking for would show as name "HTTP_CUSTOM_ID" and I could see it, with it's value in the ALL_HTTP and ALL_RAW, but when I tried to pull that specific value, it would return an empty string. The solution I stumbled on (by talking to someone else here at work who had gone through a similar situation with the same service I was trying to accommodate is to use:
<%=Request.ServerVariables("HEADER_CUSTOM_ID")%>
When viewing the full header, nothing led me to use the HEADER prefix instead of the HTTP, in fact, it led me opposite. And I never found any mention of this anywhere searching online either. So I'm posting my own answer to my question here so it is on the web.
For the sake of expedience, why not just parse Request.ServerVariables("ALL_RAW") yourself?
There is a better way than parsing each item yourself. Look at the values in Request.ServerVariables("ALL_HTTP") and find the header you need but named a bit different.
All HTTP headers start with HTTP_. I was looking for If-None-Match and it was in the collection as HTTP_IF_NONE_MATCH. To get the value I used Request.ServerVariables("HTTP_IF_NONE_MATCH").

is it possible to issue dynamic include in asp-classic?

I mean, like php'h include...
something like
my_file_to_be_included = "include_me.asp"
-- >
for what I've seen so far, there are a couple of alternatives, but every one of them has some sort of shortcoming...
what I'm trying to figure out is how to make a flexible template system... without having to statically include the whole thing in a single file with a loooooong case statement...
here there are a couple of links
a solution using FileSysmemObject, just lets you include static pages
idem
yet another one
same thing from adobe
this approach uses Server.Execute
but it has some shortcomings I'd like to avoid... seems like (haven't tried yet) Server.Execute code runs in another context, so you can't use it to load a functions your are planning to use in the caller code... nasty...
same thing
I think this one is the same
this looks promising!!!
I'm not sure about it (couldn't test it yet) but it seems like this one dinamycally handles the page to a SSDI component...
any idea???
No you can't do a dyanmic include, period.
Your best shot at this is a server.execute and passing whatever state it needs via a Session variable:-
Session("callParams") = BuildMyParams() 'Creates some sort of string
Server.Execute(my_file_to_be_included)
Session.Contents.Remove("callParams")
Improved version (v2.0):
<%
' **** Dynamic ASP include v.2.0
function fixInclude(content)
out=""
if instr(content,"#include ")>0 then
response.write "Error: include directive not permitted!"
response.end
end if
content=replace(content,"<"&"%=","<"&"%response.write ")
pos1=instr(content,"<%")
pos2=instr(content,"%"& ">")
if pos1>0 then
before= mid(content,1,pos1-1)
before=replace(before,"""","""""")
before=replace(before,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
before=vbcrlf & "response.write """ & before & """" &vbcrlf
middle= mid(content,pos1+2,(pos2-pos1-2))
after=mid(content,pos2+2,len(content))
out=before & middle & fixInclude(after)
else
content=replace(content,"""","""""")
content=replace(content,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
out=vbcrlf & "response.write """ & content &""""
end if
fixInclude=out
end function
Function getMappedFileAsString(byVal strFilename)
Dim fso,td
Set fso = Server.CreateObject("Scripting.FilesystemObject")
Set ts = fso.OpenTextFile(Server.MapPath(strFilename), 1)
getMappedFileAsString = ts.ReadAll
ts.close
Set ts = nothing
Set fso = Nothing
End Function
execute (fixInclude(getMappedFileAsString("included.asp")))
%>
Sure you can do REAL classic asp dynamic includes. I wrote this a while back and it has opened up Classic ASP for me in a whole new way. It will do exactly what you are after, even though people seem to think it isn't possible!
Any problems just let me know.
I'm a bit rusty on classic ASP, but I'm pretty sure you can use the Server.Execute method to read in another asp page, and then carry on executing the calling page. 15Seconds had some basic stuff about it - it takes me back ...
I am building a web site where it would have been convenient to be able to use dynamic includes. The site is all ajax (no page reloads at all) and while the pure-data JSON-returning calls didn't need it, all the different html content for each different application sub-part (window/pane/area/form etc) seems best to me to be in different files.
My initial idea was to have the ajax call be back to the "central hub" main file (that kicks the application off in the first place), which would then know which sub-file to include. Simply including all the files was not workable after I realized that each call for some possibly tiny piece would have to parse all the ASP code for the entire site! And using the Execute method was not good, both in terms of speed and maintenance.
I solved the problem by making the supposed "child" pages the main pages, and including the "central hub" file in each one. Basically, it's a javascript round-trip include.
This is less costly than it seems since the whole idea of a web page is that the server responds to client requests for "the next page" all the time. The content that is being requested is defined in scope by the page being called.
The only drawback to this is that the "web pieces" of the application have to live partly split apart: most of their content in a real named .asp file, but enough of their structure and relationship defined in the main .asp file (so that, for example, a menu item in one web piece knows the name to use to call or load another web piece and how that loading should be done). In a way, though, this is still an advantage over a traditional site where each page has to know how to load every other page. Now, I can do stuff like "load this part (whether it's a whole page or otherwise) the way it wants to be loaded".
I also set it up so each part can have its own javascript and css (if only that part needs those things). Then, those files are included dynamically through javascript only the first time that part is loaded. Then if the part is loaded repeatedly it won't incur an extra overhead.
Just as an additional note. I was getting weird ASCII characters at the top of the pages that were using dynamic includes so I found that using an ADODB.Stream object to read the include file eliminated this issue.
So my updated code for the getMappedFileAsString function is as follows
Function getMappedFileAsString(byVal strFilename)
Dim fso
Set fso = CreateObject("ADODB.Stream")
fso.CharSet = "utf-8"
fso.Open
fso.LoadFromFile(Server.MapPath(strFilename))
getMappedFileAsString = fso.ReadText()
'Response.write(getMappedFileAsString)
'Response.End
Set fso = Nothing
End Function

How to stop .NET from encoding an XML string with XML.Serialization

I am working with some Xml Serialization in ASP.NET 2.0 in a web service. The issue is that I have an element which is defined such as this:
<System.Xml.Serialization.XmlElementAttribute(Form:=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable:=True)> _
Public Property COMMENTFIELD() As String
Get
Return CommentField ' This is a string
End Get
Set(ByVal value as String)
CommentField = value
End Set
End Property
Elsewhere in code I am constructing a comment and appending
as a line-break (according to the rules of the web service we are submitting to) between each 'comment', like this: (Please keep in mind that
is a valid XML entity representing character 10 (Line Feed I believe).
XmlObject.COMMENTFIELD = sComment1 & "
" & sComment2
The issue is that .NET tries to do us a favor and encode the & in the comment string which ends up sending the destination web service this: &#xA;, which obviously isn't what we want.
Here is what currently happens:
XmlObject.COMMENTFIELD = sComment1 & "
" & sComment2
Output:
<COMMENTFIELD>comment1 &#xA comment2</COMMENTFIELD>
Output I NEED:
<COMMENTFIELD>comment1
comment2</COMMENTFIELD>
The Question Is: How do I force the .NET runtime to not try and do me any favors in regards to encoding data that I already know is XML compliant and escaped already (btw sComment1 and sComment2 would already be escaped). I'm used to taking care of my XML, not depending on something magical that happens to escape all my data behind my back!
I need to be able to pass valid XML into the COMMENTFIELD property without .NET encoding the data I give it (as it is already XML). I need to know how to tell .NET that the data it is receiving is an XML String, not a normal string that needs escaped.
If you look at the XML spec section 2.4, you see that the & character in an element's text always used to indicate something escaped, so if you want to send an & character, it needs to be escaped, e.g., as & So .Net is converting the literal string you gave it into valid XML.
If you really want the web service to receive the literal text &, then .NET is doing the correct thing. When the web service processes the XML it will convert it back to the same literal string you supplied on your end.
On the other hand, if you want to send the remote web service a string with a newline, you should just construct the string with the newline:
XmlObject.COMMENTFIELD = sComment1 & "\n" & sComment2
.Net will do the correct thing to make sure this is passed correctly on the wire.
It is probably dangerous to mix two different encoding conventions within the same string. Since you have your own convention I recommend explicitly encoding the whole string when it is ready to send and explicitly decoding it on the receiving end.
Try the HttpServerUtility.HtmlEncode Method (System.Web) .
+tom

Resources