WebRequest/POST question on extracting specific data from a website - post

I am trying to gather data on specific events from a company website: http://pipeline.kindermorgan.com/infoposting/notices.aspx?type=CRIT
I have worked a lot of similar websites but so far they have been pretty simple and it’s just a matter of going to the website and working with the response stream. In this case the website requires you to select a value from the first combo box (TSP/TSP Name). Without any info being passed, the URL will return the data associated with the first item in the list. I really need to be able to get the data associated with any of the items in the list.
Here is the code I have been using thus far but it fails with a Server Error 500 so I am guessing that either I did not form the POST properly or am missing some data in the post data):
For the page I have listed above I just want to get a response stream with the table of the notices for a particular TSP from the combo box (starting with Trailblazer). I know the control is “ctl00$ContentPlaceHolder1$ddlpipeline” and the value I want to send is 24. When I navigate via IE, I also have to press the “Retrieve” button.
When I look at the POST request using FireBug, I notice that there are a lot of other target/values included. I’m not sure if I need to send all of those as well and (having never done a POST before) I am not sure how to format the data in the POST to do that.
Bear with me if this request seems odd. I am more of a database person and am looking to automate a lot of the stuff we are required to look at manually every day. Any help would be greatly appreciated!
var encoding = new ASCIIEncoding();
var postData = "ctl00$ContentPlaceHolder1$ddlpipeline=24";
byte[] data = encoding.GetBytes(postData);
string RemoteURI = "http://pipeline.kindermorgan.com/infoposting/notices.aspx?type=CRIT";
var myRequest = (HttpWebRequest)WebRequest.Create(RemoteURI);
myRequest.Method = "POST";
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.ContentLength = data.Length;
var newStream = myRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
var response = myRequest.GetResponse();
var responseStream = response.GetResponseStream();
var responseReader = new StreamReader(responseStream);

I actually resolved the issue and there were a number of things I found out in the process that I will share for the benefit of others who may look at this thread.
First, I had to build the POST data exactly as it appears in the POST in a browser (I used Firebug to see the POST data). This meant getting the hidden arguments as well (particularly VIEWSTATE and EVENTVALIDATION). I was able to get these by just downloading the default page source for the page (by the way, i do this in the code because it is not static for this site) and parsing out the values for the hidden fields. I then build the POST data string with any changes I may have (in my case changing the date was important but in the future I may change other things).
Now the thing that really had me stumped. I confirmed that the POST data string was exactly the same as the one sent by FireFox/FireBug through a character by character comparison and it still wouldn't work. I then remembered in a previous scraping case that I had to set the user agent.
So here is the code I ended up with:
string postData = String.Format("__EVENTTARGET=&__EVENTARGUMENT=&__LASTFOCUS="
+ "&__VIEWSTATE={0}"
+ "&ctl00%24UltraWebTree1={1}"
+ "&ctl00%24ContentPlaceHolder1%24ddlNoticeCategory={2}"
+ "&ctl00%24ContentPlaceHolder1%24ddlpipeline={3}"
+ "&ctl00%24ContentPlaceHolder1%24Button1={4}"
+ "&ctl00%24ContentPlaceHolder1%24tbDate={5}"
+ "&ctl00%24ContentPlaceHolder1%24ddlNoticeType={6}"
+ "&ctl00%24ContentPlaceHolder1%24tbSubject={7}"
+ "&ctl00%24ContentPlaceHolder1%24ddlNoticeSubType={8}"
+ "&ctl00%24ContentPlaceHolder1%24ddlOrderBy={9}"
+ "&ctl00%24ContentPlaceHolder1%24hfmode={10}"
+ "&ctl00%24ContentPlaceHolder1%24hfODSCommand={11}&ctl00%24hfPipeline={12}"
+ "&__PREVIOUSPAGE={13}&__EVENTVALIDATION={14}",
viewstate, webtree, noticecategory, pplcode,
button1, todaydate, noticetype, subject,
noticesubtype, orderby, hfmode, hfODSCommand,
hfPipeline, previouspage, eventvalidation);
var encoding = new ASCIIEncoding();
byte[] data = encoding.GetBytes(postData);
var myRequest = (HttpWebRequest)WebRequest.Create(RemoteURI);
myRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)" ;
myRequest.Method = "POST" ;
myRequest.ContentType = "application/x-www-form-urlencoded";
myRequest.ContentLength = data.Length;
var newStream = myRequest.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
var myresponse = myRequest.GetResponse();
var responseStream = myresponse.GetResponseStream();
var responseReader = new StreamReader(responseStream);
string webpagesource = responseReader.ReadToEnd();
Hope this helps someone else.

Related

How to parse attachment values with strongGrid inbound webhook

Hello there I have setup successfully inbound webhook with strongGrid in net core 3.1.
The endpoint gets called and I want to parse value inside the attachment which is csv file.
The code I am using is following
var parser = new WebhookParser();
var inboundEmail = await parser.ParseInboundEmailWebhookAsync(Request.Body).ConfigureAwait(false);
await _emailSender.SendEmailAsyncWithSendGrid("info#mydomain.com", "ParseWebhook1", inboundEmail.Attachments.First().Data.ToString());
Please note I am sending an email as I don t know how to debug webhook with sendgrid as I am not aware of any cli.
but this line apparently is not what I am looking for
inboundEmail.Attachments.First().Data.ToString()
I am getting this on my email
Id = a3e6a543-2aee-4ffe-a36a-a53k95921998, Tag = HttpMultipartParser.MultipartFormDataParser.ParseStreamAsync, Length = 530 bytes
the csv I need to parse has 3 fields Sku productname and quantity I'd like to get sku values.
Any help would be appreciated.
The .Data property contains a Stream and invoking ToString on a stream object does not return its content. The proper way to read the content of a stream in C# is something like this:
var streamReader = new StreamReader(inboundEmail.Attachments.First().Data);
var attachmentContent = await streamReader.ReadToEndAsync().ConfigureAwait(false);
As far as parsing the CSV, there are literally thousands of projects on GitHub and hundreds on NuGet with the keyword 'CSV'. I'm sure one of them will fit your needs.

Xulrunner Browser Posting data via loadURI()

I have XULrunner opening a browser window that loads a XUL page from my local server. I am trying to post some data back to my PHP but with little success. I am just using the example at https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Post_data_to_window
Here's what my javascript looks like
var params = obj.getAttribute('params');
var url = obj.getAttribute('url');
alert(params + ' - ' + url);
const Cc = Components.classes;
const Ci = Components.interfaces;
var stringStream = Cc['#mozilla.org/io/string-input-stream;1'].createInstance(Ci.nsIStringInputStream);
stringStream.data = params;
var postdata = Cc['#mozilla.org/network/mime-input-stream;1'].createInstance(Ci.nsIMIMEInputStream);
postdata.addHeader('Content-Type', 'application/x-www-form-urlencoded');
postdata.addContentLength = true;
postdata.setData(stringStream);
document.getElementById('mainbrowser').loadURI(url, null, postdata, null);
Without trying to confuse the matter too much, this is obviously part of a much bigger picture. The only part not shown, that is relevant, is where obj is derived. Basically it is a temporary XUL element that has all the parameters stored in it for easy access as I pass them around to different functions in my javascript. Also the params is in the format of name1=data1&name2=data2.
I know it is working up to the alert as it does outputs the parameters that I am sending. I am also sure the browser is being reloaded as the data I entered in the form is being cleared each time I submit it. But in my PHP if I output the contents of $_POST there is nothing.
I did have this working using XMLHttpRequest but it wasn't ideal for how I needed things to work. So I am hoping to get his method working.

QuickBooks Online querying with filter returns 401 everytime

I've had success creating objects with POST and Content-Type application/xml
I've also had success querying using Content-Type application/x-www-form-urlencoded with a blank request body which returns all of the object type depending on which URI I specify.
I can also get the same to work with something like PageNum=1&ResultsPerPage=1 in the request body and I have figured out how to incorporate that into the signature so I get a valid response.
However no matter how I format it, I cannot get anything other than a 401 response when I try to use a filter (something basic like Filter=FAMILYNAME :EQUALS: Doe). I've read over the OAuth Core 1.0 Revision A specifications on how all parameter names and values are escaped using the [RFC3986] percent-encoding. However I feel like I'm missing a step or formatting incorrectly. I've seen inconsistent information in my searching through Intuit's forums on what exactly is the proper format.
Any help on this would be greatly appreciated. I've been struggling with this for a good week now.
The response I get when trying to use a filter is:
HTTP Status 401 - message=Exception authenticating OAuth; errorCode=003200; statusCode=401
----Update----
I'm am seeing the same error when I try to use filters with the New IPP Developer Tools - IPP API Explorer. I'm using the IDS V2 QBO API Explorer. I'm able to use that tool to do a retrieve all Post and the response shows all of my customers, but when I try to use a filter I get :
Server Error
401 - Unauthorized: Access is denied due to invalid credentials.
You do not have permission to view this directory or page using the credentials that you supplied.
Any Ideas? If I'm getting the same error from the API Explorer tool, it makes me think the problem is something else entirely.
----Final Update----
I have finally had success with filters and I believe I have figure out what my problem was. I was always suspicious that I was able to get queries with pagination like "PageNum=1&ResultsPerPage=1" to work, but could not get something like "Filter=FAMILYNAME :EQUALS: Doe". I suspected there problem was with the white space in the filter format. What threw me off tracking this down earlier was that I could not get the filters to work in the IDS V2 QBO API Explorer. That made me suspect there was something else going on. I decided to ignore the API Explorer all together and focus on why I could get it to work the one way but no the other.
I believe my problem came down to improper encoding of the Filter's value in the signature. That explains the 401 invalid signature errors I was getting.
"Filter=Name :EQUALS: Doe" becomes "Filter=Name%20%3AEQUALS%20%3ADoe" after normalization.
Percent-Encoding that should give "Filter%3DName%2520%253AEQUALS%2520%253ADoe".
In essence you have to "double" encode the blank space and the colons, but not the equal sign. I tried many permutations of doing the encoding, but believe my mistake was that I was either not "double" encoding, or when I was double encoding I was including the '=' sign. Either way breaks your signature. Thanks for everyone's input.
I believe my problem came down to improper encoding of the Filter's value in the signature. That explains the 401 invalid signature errors I was getting.
I used an online tool to take me through the steps in properly signing an Oauth request. While going through those steps I realized my problem was with the steps where you normalize the request parameters and then percent-encode them. I was including the '=' of the filter in the normalization step, which breaks your signature. The tool I used can be found at:
http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iv-signing-requests/
Thanks for everyone's input.
Do you get a 401 with the same request in the API Explorer?
http://ippblog.intuit.com/blog/2013/01/new-ipp-developer-tool-api-explorer.html
Also, are you using the static base URL or retrieving it at runtime?
https://ipp.developer.intuit.com/0010_Intuit_Partner_Platform/0050_Data_Services/0400_QuickBooks_Online/0100_Calling_Data_Services/0010_Getting_the_Base_URL
If you are using the static base URL, try switching to the runtime base URL to see if you still get the error.
peterl answered one of my questions on here that may also answer yours. I had been trying to put the Filters in the body when they should have gone into the header. Here was peterl's code sample for getting all unpaid invoices (open balance greater than 0.00) for a particular customer.
http://pastebin.com/raw.php?i=7VUB6whp
public List<Intuit.Ipp.Data.Qbo.Invoice> GetQboUnpaidInvoices(DataServices dataServices, int startPage, int resultsPerPage, IdType CustomerId)
{
StringBuilder requestXML = new StringBuilder();
StringBuilder responseXML = new StringBuilder();
var requestBody = String.Format("PageNum={0}&ResultsPerPage={1}&Filter=OpenBalance :GreaterThan: 0.00 :AND: CustomerId :EQUALS: {2}", startPage, resultsPerPage, CustomerId.Value);
HttpWebRequest httpWebRequest = WebRequest.Create(dataServices.ServiceContext.BaseUrl + "invoices/v2/" + dataServices.ServiceContext.RealmId) as HttpWebRequest;
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.Headers.Add("Authorization", GetDevDefinedOAuthHeader(httpWebRequest, requestBody));
requestXML.Append(requestBody);
UTF8Encoding encoding = new UTF8Encoding();
byte[] content = encoding.GetBytes(requestXML.ToString());
using (var stream = httpWebRequest.GetRequestStream())
{
stream.Write(content, 0, content.Length);
}
HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
using (Stream data = httpWebResponse.GetResponseStream())
{
Intuit.Ipp.Data.Qbo.SearchResults searchResults = (Intuit.Ipp.Data.Qbo.SearchResults)dataServices.ServiceContext.Serializer.Deserialize<Intuit.Ipp.Data.Qbo.SearchResults>(new StreamReader(data).ReadToEnd());
return ((Intuit.Ipp.Data.Qbo.Invoices)searchResults.CdmCollections).Invoice.ToList();
}
}
protected string GetDevDefinedOAuthHeader(HttpWebRequest webRequest, string requestBody)
{
OAuthConsumerContext consumerContext = new OAuthConsumerContext
{
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
SignatureMethod = SignatureMethod.HmacSha1,
UseHeaderForOAuthParameters = true
};
consumerContext.UseHeaderForOAuthParameters = true;
//URIs not used - we already have Oauth tokens
OAuthSession oSession = new OAuthSession(consumerContext, "https://www.example.com",
"https://www.example.com",
"https://www.example.com");
oSession.AccessToken = new TokenBase
{
Token = accessToken,
ConsumerKey = consumerKey,
TokenSecret = accessTokenSecret
};
IConsumerRequest consumerRequest = oSession.Request();
consumerRequest = ConsumerRequestExtensions.ForMethod(consumerRequest, webRequest.Method);
consumerRequest = ConsumerRequestExtensions.ForUri(consumerRequest, webRequest.RequestUri);
if (webRequest.Headers.Count > 0)
{
ConsumerRequestExtensions.AlterContext(consumerRequest, context => context.Headers = webRequest.Headers);
if (webRequest.Headers[HttpRequestHeader.ContentType] == "application/x-www-form-urlencoded")
{
Dictionary<string, string> formParameters = new Dictionary<string, string>();
foreach (string formParameter in requestBody.Split('&'))
{
formParameters.Add(formParameter.Split('=')[0], formParameter.Split('=')[1]);
}
consumerRequest = consumerRequest.WithFormParameters(formParameters);
}
}
consumerRequest = consumerRequest.SignWithToken();
return consumerRequest.Context.GenerateOAuthParametersForHeader();
}
You can also see my original Question Here on StackOverflow: Query for All Invoices With Open Balances using QuickBooks Online (QBO) Intuit Partner Platform (IPP) DevKit.

Sending Post Data through a HTTP Request POST

I am trying to post data from a Textarea to a classic ASP script that updates the MS SQL on the local machine then posts to a PHP script on another server. However doing the below does not work, as it will cut off the data for the textarea. It has special characters in it for HTML and other data.
So my question is, how do I pass this data through a POST using ASP Classic?
I have been searching all day, so hopefully someone can enlighten me, thanks!
strUrl = "http://www.example.com/index.php"
requestData = request("request")
requestData2 = request("request2")
strData = "request=" & requestData & "&request2=" & requestData2
postHTML (strUrl, strData)
function postHTML (strUrl, strData)
Set xmlHttp = Server.Createobject("MSXML2.ServerXMLHTTP")
xmlHttp.Open "POST", strUrl, False
xmlHttp.setRequestHeader "User-Agent", "asp httprequest"
xmlHttp.setRequestHeader "content-type", "application/x-www-form-urlencoded"
xmlHttp.Send strData
postHTML = xmlHttp.responseText
xmlHttp.abort()
set xmlHttp = Nothing
end function
For example if an & is in the requestdata2, anything after that & is truncated, because it is thinking it is starting a new string. But I want to be able to pass this along.
Only Solution I can think of as of right now: do a string replace for special characters such as = and & and restore them with another string replace on the php server. This however is not what I want to accomplish this task. I would like the correct way of sending a post.
You need to URL encode the parameter values, so change this line...
strData = "request=" & requestData & "&request2=" & requestData2
...to...
strData = "request=" & Server.UrlEncode(requestData) & "&request2=" & Server.UrlEncode(requestData2)
The receiving server should automatically decode the values.

What object (key-value) can I use for actionscript's URLRequest/Loader classes?

I am trying to get my Actionscript program to turn in a key-value (more specifically: a key, value1, value2) object into a server. I am doing the html request properly, but I'm not sure what kind of object to send; can anyone help?
--Thanks
When I understand correctly you want to post an object to the server, which has 1 key and multiple values. The latter is not supported by a HTTP_POST/GET call, you could however use something as AMF to send a VO from Flash over to a server and decode the AMF object on the server. Not sure whether or not that is where you are looking for, or you just want to post 2 values to a server.
Posting 2 values to a server is simple, but it requires two keys.
public function URLVariablesExample() {
var url:String = "http://www.domain.com/script.php";
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
variables.keyOne = new Date().getTime();
variables.keyTwo = "Something";
request.data = variables;
navigateToURL(request);
}

Resources