I am currently writing an iPhone application that will push a username and password to a website to retrieve the HTML source code of the page which loads. I include login information in NSString *post.
When I NSLog the _responseData instance variable in the connectionDidFinishLoading method, the console prints a long series of eight digit hexadecimal numbers which I assume are some type of address or encrypted HTML (3c21444f 43545950 45206874 6d6c2050 55424c49 4320222d 2f2f5733...).
What should I do to convert/decrypt the addresses into HTML code or otherwise retrieve the HTML code of the webpage which loads?
My ViewController conforms to the NSURLConnectionDelegate protocol and includes the following code:
#interface ViewController : UIViewController<NSURLConnectionDelegate>
{
NSMutableData *_responseData;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
_responseData = [[NSMutableData alloc] init];
NSLog(#"Received response");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
NSLog(#"Received data");
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
//NSString *html=[NSString stringWithContentsOfURL:[NSURL URLWithString:#"https://grades.bsd405.org/Pinnacle/Gradebook/InternetViewer/GradeSummary.aspx?&EnrollmentId=770595&TermId=127463&ReportType=0&StudentId=114040"] encoding:NSASCIIStringEncoding error:nil];
NSLog(#"Finished loading");
//PRINT HTML:
NSLog(#"Data: %#",_responseData);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
NSLog(#"Failed to load");
}
- (IBAction)goPressed:(UIButton *)sender {
NSString *post = #"__LASTFOCUS&__EVENTTARGET&__EVENTARGUMENT&__VIEWSTATE=/wEPDwUJNTkxNzI3MDIzD2QWAmYPZBYCA
gMPZBYGAgEPZBYCAgkPZBYCAgEPZBYIAgMPFgIeB1Zpc2libGVoZAIFDxYCHwBoZAIHDxYCHwBoZAIJDxYCHgVzdH
lsZQUjdmVydGljYWwtYWxpZ246bWlkZGxlO2Rpc3BsYXk6bm9uZTtkAgMPDxYCHwBoZGQCBQ9kFghmD2QWAgINDxY
CHgVjbGFzcwUQc2luZ2xlU2Nob29sTGlzdBYCAgEPZBYCAgEPEGQPFgFmFgEQBQ5EZWZhdWx0IERvbWFpbgUIUGlu
bmFjbGVnZGQCAg9kFgICEw9kFgICAQ9kFgICAQ8QZGQWAGQCBw8PFgIeBFRleHQFIFBpbm5hY2xlIEdyYWRlIDIwM
TIgV2ludGVyIEJyZWFrZGQCCA8PFgIfAwU3Q29weXJpZ2h0IChjKSAyMDEzIEdsb2JhbFNjaG9sYXIuICBBbGwgcm
lnaHRzIHJlc2VydmVkLmRkZP/l6irI9peZfyqpKjk3fwLuEbos&__EVENTVALIDATION=/wEWBgKjnbqUCQLnksmg
AQKTpbWbDgLB5+KIBAL4xb20BAK20ZqiCel6sQLBsF1W3XHOxpgq+tJj+Rx2&ctl00$ContentPlaceHolder$Use
rname=TESTUSERNAME&ctl00$ContentPlaceHolder$Password=TESTPASSWORD&ctl00$ContentPlaceHolde
r$lstDomains=Pinnacle&ctl00$ContentPlaceHolder$LogonButton=Sign
in&PageUniqueId=2dacba26-
bb0d-412f-b06a-e02caf039c4b";
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"https://grades.bsd405.org/Pinnacle/Gradebook/Logon.aspx?ReturnUrl=%2fPinnacle%2fGradebook%2fDefault.aspx"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
[NSURLConnection connectionWithRequest:request delegate:self];
}
The NSLog of your NSData displays the object's description, which a hexadecimal string of the underlying binary data:
3c21444f 43545950 45206874 6d6c2050 55424c49 4320222d 2f2f5733 ...
Translates to a string of
<!DOCTYPE html PUBLIC "-//W3 ...
To get the NSString from the NSData, you do:
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Related
I'm a beginner in the area to work with database on iOS. However I could find a way to connect to a MySQL database, download and parse the json feed. Now in iOS 9, I can't use NSURLConnection anymore, that's why I have to replace it with NSURLSession. I saw many tutorials for example this here. So far, I was not able to replace it. Because I'm under time pressure, I can't waste more time to do this. Is here anyone who could help me to replace it?
My code looks exactly like this:
- (void)downloadItems
{
// Download the json file
NSURL *jsonFileUrl = [NSURL URLWithString:#"http://myhost.ch/test.php"];
// Create the request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:jsonFileUrl];
// Create the NSURLConnection
[NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
#pragma mark NSURLConnectionDataProtocol Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// Initialize the data object
_downloadedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the newly downloaded data
[_downloadedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Create an array to store the locations
NSMutableArray *_locations = [[NSMutableArray alloc] init];
// Parse the JSON that came in
NSError *error;
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:_downloadedData options:NSJSONReadingAllowFragments error:&error];
// Loop through Json objects, create question objects and add them to our questions array
for (int i = 0; i < jsonArray.count; i++)
{
NSDictionary *jsonElement = jsonArray[i];
// Create a new location object and set its props to JsonElement properties
Location *newLocation = [[Location alloc] init];
newLocation.idS = jsonElement[#"idStatistic"];
newLocation.temp = jsonElement[#"temp"];
newLocation.hum = jsonElement[#"hum"];
newLocation.date_time = jsonElement[#"date_time"];
// Add this question to the locations array
[_locations addObject:newLocation];
}
// Ready to notify delegate that data is ready and pass back items
if (self.delegate)
{
[self.delegate itemsDownloaded:_locations];
}
}
You can try this,
{
NSURL *url = [NSURL URLWithString:#"http://myhost.ch/test.php"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
[theRequest setHTTPMethod:#"POST"];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:theRequest
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
responseDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSLog(#"Result:%#", responseDict);
}];
[task resume];
}
So i work with UICollectionView with my JSON. I write this code for parse, but i am not understand for why it's not work. My JSON have ([jsontest2] after key "imageMain").
So i paste my code, please help me:
#property (nonatomic,strong) NSMutableArray *patternImagesArray;
#end
#implementation ViewController
#synthesize patternImagesArray = _patternImagesArray;
NSURLConnection *connection;
NSMutableData *webdata;
Try to get data from JSON:
-(void) viewDidLoad{
_patternImagesArray = [[NSMutableArray alloc] init];
NSURL *url = [NSURL URLWithString:#"site"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (connection) {
webdata = [[NSMutableData alloc]init];
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[webdata setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webdata appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
JSON parse:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSDictionary *allDataDictionary = [NSJSONSerialization JSONObjectWithData:webdata options:0 error:nil];
NSArray *tmp =[allDataDictionary objectForKey:#"jsontest2"];
if (tmp.count>0){
for (NSDictionary *diction in tmp) {
[self.patternImagesArray addObject:diction];
}
NSLog(#"%#", self.patternImagesArray);
}
[self.collectionView reloadData];
}
Some customize things:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
PatternView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"PatternCell" forIndexPath:indexPath];
NSString *myPatternString = [[self.patternImagesArray objectAtIndex:indexPath.row] valueForKey:#"thumb"];
NSLog(#"myPatternString %#",myPatternString);
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:myPatternString]];
cell.patternImageView.image = [UIImage imageWithData:data];
return cell;
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return [self.patternImagesArray count];
}
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
return CGSizeMake(100.0, 100.0);
}
You are abusing the variable "array" for two totally different purposes.
The underlying reason is that you haven't bothered to find reasonable names for variables. "array" is actually a global variable. It's not only accessible from any code within your file, but from any code anywhere in your program. Look at this bit of code:
NSDictionary *allDataDictionary =[NSJSONSerialization JSONObjectWithData:_webdata
options:kNilOptions error:nil];
array =[allDataDictionary objectForKey:#"jsontest2"];
for (array in allDataDictionary) {
}
You first parse the JSON data to allDataDictionary (you don't bother checking for errors). You access one key "jsontest2" from the dictionary and store it into the global variable "array". Whatever was in "array" before is now gone.
Then you have a for-loop, using the same global variable as the loop variable! That's total nonsense. But you also need to realise that this will iterate over the keys in your dictionary, so array is now an NSString and not an array anymore.
After that your code gets worse...
Go through your code line by line. Every line, think about what it is doing. There are many severe problems there.
This my code:
#import "MainClass.h"
#implementation MainClass
- (IBAction)actionButton:(id)sender {
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL
URLWithString:#"https://login.dnevnik.ru/auth"]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15.0];
request.HTTPMethod = #"POST";
NSString *username = _loginLogin.text;
NSString *password= _passwordLogin.text;
GlobalUserName = username;
GlobalPassword = password;
/*NSUserDefaults *loginData = [NSUserDefaults standardUserDefaults];
NSString *username1 = [loginData objectForKey:#"username"] ;
NSString *password1 = [loginData objectForKey:#"password"];*/
NSString * param = [NSString stringWithFormat:#"&username=%#&password=%#", username, password];
request.HTTPBody = [param dataUsingEncoding:NSUTF8StringEncoding];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
_otvet.text = #"Connection setup";
NSLog(#"ama ama");
}
else
{
_otvet.text=#"Problem with connection";
NSLog(#"ama ama faza");
}
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Ошибка" message:#"Problem with intrnet" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString * data = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
if ([data isEqual: #"OK"]) {
_otvet.text = #"Yeah";
NSLog(#"Yeah");
}
else
{
NSLog(#"Error %#,%#",GlobalUserName,GlobalPassword);
}
}
Show Message,what NSLog(#"Error %#,%#",GlobalUserName,GlobalPassword) because method isEqual say what my data are not the same.What should i do?and I'm not sure that sending the right site login and password. Tell me how to determine where(whither) to send the data, I don't have site! Website www.dnevnik.ru!!
You need to setup the parameter string properly.
Here in your code
NSString * param = [NSString stringWithFormat:#"&username=%#&password=%#", username, password];
request.HTTPBody = [param dataUsingEncoding:NSUTF8StringEncoding];
This looks like you want to use content type application/x-www-form-urlencoded. However, the parameter string starts with a "&" - and this is definitely an error.
When using parameters like this with a content type application/x-www-form-urlencoded, I would suggest to create your parameters as (unencoded) NSString key/value pairs, create a NSDictionary and use the following helper method described in the answer here (API POST method not saving data in sql server) which creates a properly encoded parameter string which you can add to the body.
Don't forget to set the "Content-Type" header to application/x-www-form-urlencoded.
I spent a lot of time for research on POST Requests using Cocoa.
I found some code that looked good. I changed it like it fits my needs. But the code didn't work and I can't find the bug because I'm pretty new to cocoa.
Here is my code.
- (IBAction)sendForm:(id)sender
{
NSLog(#"web request started");
NSString *post = [NSString stringWithFormat:#"firstName=%#&lastName=%#&eMail=%#&message=%#", firstName.stringValue, lastName.stringValue, eMail.stringValue, message.stringValue];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"myDomain/form.php"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(theConnection)
{
webData = [[NSMutableData data] retain];
NSLog(#"connection initiated");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[webData appendData:data];
NSLog(#"connection received data");
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"connection received response");
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
if([ne statusCode] == 200)
{
NSLog(#"connection state is 200 - all okay");
NSString *html = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
[[webView mainFrame] loadHTMLString:html baseURL:[NSURL URLWithString:#"myDomain"]];
}
}
But the only two NSLog messages I receive are "web request started" and "connection initiated".
So I think - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data and - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)responseare not called.
Can anybody help me with this issue?
Thanks for help, Julian
You almost did it correctly!
I can see the post is a year old but in the hope that it may help others and for my own reference, I am posting this here.
Apple's documentation for connection:didReceiveResponse: says :-
Sent when the connection has received sufficient data to construct the
URL response for its request.
As with most Apple documentation this too is confusing and maybe misleading. Usually when we have "sufficient data to construct the URL response" means we have the complete response which further means that we have response body too; which is universally considered part of the response.
However in this case the NSHTTPURLResponse object does not have a body. So my guess is, what Apple means is - connection:didReceiveResponse: is invoked when we have received the response header which has "sufficient" data to let us known everything about the response, except the actual data (body).
In fact many times you will notice that connection:didReceiveData: gets called after connection:didReceiveResponse: is invoked.
So, we can modify your code as below :-
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSLog(#"web request started");
NSString *post = [NSString stringWithFormat:#"firstName=%#&lastName=%#&eMail=%#&message=%#", firstName.stringValue, lastName.stringValue, eMail.stringValue, message.stringValue];
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
NSString *postLength = [NSString stringWithFormat:#"%ld", (unsigned long)[postData length]];
NSLog(#"Post data: %#", post);
NSMutableURLRequest *request = [NSMutableURLRequest new];
[request setURL:[NSURL URLWithString:#"https://example.com/form.php"]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(theConnection) {
webData = [NSMutableData data];
NSLog(#"connection initiated");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[webData appendData:data];
NSLog(#"connection received data");
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"connection received response");
NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
if([ne statusCode] == 200) {
NSLog(#"connection state is 200 - all okay");
} else {
NSLog(#"connection state is NOT 200");
}
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Conn Err: %#", [error localizedDescription]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Conn finished loading");
NSString *html = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding];
NSLog(#"OUTPUT:: %#", html);
}
Have you tried to implement the error delegate method?
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// do something with error
}
It can happen that you don't have an internet connection, or something else is wrong before NSURLConnection is able to establish a connection. In this case you will not receive a http response or any other data. The error will provide more information.
[edit]
I just noticed the URL in the example code doesn't contain a host name. If this is the exact code you are using make sure you send the request to a correct URL.
// Replace
[NSURL URLWithString:#"myDomain/form.php"]
// with a correct url like
[NSURL URLWithString:#"http://mydomain.com/form.php"];
An error delegate method will actually provide you with an error that complains about a wrong URL.
I would like to parse a webpage to get the content of a table on that page. However, the table is created by calling document.write() and several javascript functions. i.e. when I load the URL request of that page, the source that I get contains no html tags of that table. Is it possible to get the source of the final page (i.e. the source containing the html tags of the table I want)? And it's very curious that I can view the "final page source" in safari Browser's Developer Tools but not the source of the page.
this is the source of the page the source
You should use implement the NSConnectionDataDelegate protocol and use the NSConnection class. I believe that by the time -(void) connectionDidFinishLoading:(NSURLConnection *)connection is called, the page has finished loading completely.
-(void) requestPage
{
NSString *urlString = #"http://the.page.you.want.com";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:20.0f];
responseData = [[NSMutableData alloc] init];
connection = [[NSURLConnection connectionWithRequest:request delegate:self] retain];
delegate = target;
}
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if ([response isKindOfClass:[NSHTTPURLResponse class]])
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
//If you need the response, you can use it here
}
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[responseData release];
[connection release];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
if (connection == adCheckConnection)
{
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
//You've got all the data now
//Do something with your response string
[responseString release];
}
[responseData release];
[connection release];
}
yes, just use view generated source in firefox with the web developer extension or firebug extension