Connect to local mac server from device - ios

Im trying to connect to a ruby sinatra server that im running locally on my mac from an app using the following code:
func load(finished: #escaping ()->()) {
// Create destination URL
let destinationFileUrl = documentsUrl.appendingPathComponent("Images.zip")
//Create URL to the source file you want to download
let fileURL = URL(string: "http://waynerumble.local~waynerumble:4567/download")
//Create Session
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
} catch (let writeError) {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
finished()
} else {
print("Error took place while downloading a file. Error description: %#", (error?.localizedDescription)! as String);
finished()
}
}
task.resume()
}
If i test the app from the simulator and set the fileURL to "http://127.0.0.1:4567/download" it works fine but from device i understand this has to be different so far I've tried:
From running ifconig in terminal i get 192.168.1.254 at en1 so i tried "http://192.168.1.255:4567/download" which gave me:
[] nw_socket_connect connectx failed: [13] Permission denied
Error took place while downloading a file. Error description: %# Could not connect to the server.
Ive also tried:
"http://waynerumble.local:4567/download" which gives:
Error took place while downloading a file. Error description: %# Could not connect to the server.
"http://waynerumble.local.~waynerumble:4567/download"(waynerumble is my computer name and username) which gives:
Error took place while downloading a file. Error description: %# A server with the specified hostname could not be found.
I also have wifi internet sharing on from both ethernet and iphone. Im not sure what else to try

192.168.1.255 is a brodcast adress for your network and you should not use it.
Why dont you connect to your real IP 192.168.1.254?
To bind Sinatra app to every interface try:
class MyApp < Sinatra::Base
set :bind, '0.0.0.0'
Then http://192.168.1.254:4567/download should work.
Also remember about opening desired port in the firewall.

Related

GCDWebServer: How do I change file permissions on server for WebDAV operations? (iOS)

I'm currently trying to use GCDWebServer to host a local webpage that's requested by a WKWebView when the app starts. I want to be able to upload external files to the server by grabbing files with a UIDocumentPickerViewController while the app is running. It seems like using a separate GCDWebDAVServer on a different port is a good idea for this.
However, if I try to upload a file to the WebDAV server, I get this data from the response:
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>HTTP Error 500</title></head><body><h1>HTTP Error 500: Failed moving uploaded file to "/arbitrary.txt"</h1><h3>[NSCocoaErrorDomain] “35B890AC-7CD2-4A10-A67F-BAED3D6C34AB-3278-000005593C778876” couldn’t be moved because you don’t have permission to access “www”. (513)</h3></body></html>
Cutting out this bit for readability:
Failed moving uploaded file to "/arbitrary.txt"</h1><h3>[NSCocoaErrorDomain] “35B890AC-7CD2-4A10-A67F-BAED3D6C34AB-3278-000005593C778876” couldn’t be moved because you don’t have permission to access “www”.
www in this context is the local folder I'm serving with GCDWebServer. It has no subfolders, only files.
Here's the code I'm using in viewDidLoad:
let webContentUrl = Bundle.main.path(forResource: "www", ofType: nil)!
httpServer = GCDWebServer()
webDAVURL = "http://localhost:\(WEBDAV_PORT)/"
webDAVServer = GCDWebDAVServer(uploadDirectory: webContentUrl)
httpServer.addGETHandler(forBasePath: "/", directoryPath: webContentUrl, indexFilename: "index.html", cacheAge: 3600, allowRangeRequests: true)
httpServer.start(withPort: HTTP_PORT, bonjourName: nil)
let options: [String: Any] = [
GCDWebServerOption_Port: WEBDAV_PORT
]
do {
try webDAVServer.start(options: options)
} catch let error {
print("Could not start WebDAV server. Reason: \(error.localizedDescription)")
}
let request = URLRequest(url: URL(string: "http://localhost:\(HTTP_PORT)/")!)
webView.load(request)
And the code used for a PUT request to upload a file to the WebDAV server:
let importedFileUrl = urls.first!
do {
let data = try Data(contentsOf: importedFileUrl)
var request = URLRequest(url: URL(string: "http://localhost:\(WEBDAV_PORT)/arbitrary.txt")!)
request.httpMethod = "PUT"
let task = URLSession(configuration: .ephemeral).uploadTask(with: request, from: data) { data, response, error in
print("Data: \(String(describing: data))")
print("Response: \(String(describing: response))")
print("Error: \(String(describing: error))")
print(String(decoding: data!, as: UTF8.self))
}
task.resume()
} catch let error {
createErrorAlert(message: error.localizedDescription)
}
This doesn't have anything to do with iOS 14 local network privacy features. I tried modifying the Info.plist to include the new keys, but nothing changed. It seems like the www folder doesn't have write permissions.
Is there a feature I'm missing that lets you change file permissions in GCDWebServer, or is there a workaround? Right now the only workaround I can think of is to create a local database alongside the web servers.
The reason write permissions were not allowed is because I was serving files directly from the app bundle, which cannot be written to.
My solution was to copy the contents of that directory into the Documents directory and use WebDAV to write to that directory instead.

Why I can't access my nodejs local server from iOs simulator

I am trying to make an http request from my xcode to my local server running on nodejs. The following in a part of my iOs code.
let url = URL(string: "http://localhost.com/signup")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
print(String(data: data, encoding: .utf8)!)
}
task.resume()
I recieve the following the response
Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."
Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be
found.
I receive the first error if I use localhost.com and I receive the second error if I change the request to www.localhost.com
in this case you have to use your IP to get access to your localhost
ex: let url = URL(string: "http://192.168.1.105/signup")!
so Instead of using (localhost.com/...) you have to set the IP of your computer where you have LOCAL SERVER.

TIC TCP Conn Failed when running Swift project on my phone

I am new to Swift. I built a simple application which works fine on the simulator. I am running the same on my device (iPhone 6s with iOS 11.0.2) and it's failing to connect to server.
getting these errors:
2017-10-26 18:16:02.489134-0400 myproj[1451:206438] TIC TCP Conn Failed [1:0x1c0176800]: 1:61 Err(61)
2017-10-26 18:16:02.489771-0400 myproj[1451:206438] Task <0C30ADDC-4A0E-4815-A701-2EF0A7CF5F04>.<1> HTTP load failed (error code: -1004 [1:61])
2017-10-26 18:16:02.490293-0400 myproj[1451:206440] Task <0C30ADDC-4A0E-4815-A701-2EF0A7CF5F04>.<1> finished with error - code: -1004
Please help me understand this error.
EDIT:
Here is the code making that call to the server:
func postRequest(postData: NSDictionary, postHeaders: NSDictionary, endPoint: String,
onComplete: #escaping ((NSDictionary)->Void), callbackParams: NSDictionary = NSMutableDictionary()) {
let url:URL = baseUrl.appendingPathComponent(endPoint)
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "POST"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
var paramString = ""
for (key, value) in postData{
paramString = paramString + (key as! String) + "=" + (value as! String) + "&"
}
request.allHTTPHeaderFields = postHeaders as? [String : String]
request.httpBody = paramString.data(using: String.Encoding.utf8)
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return}
let json: Any?
do {
json = try JSONSerialization.jsonObject(with: data!, options: [])
}
catch {
return
}
var serverResponse = json as? NSDictionary
DispatchQueue.main.async{
for (key, value) in serverResponse!{
callbackParams.setValue(value, forKey: key as! String)
}
onComplete(callbackParams)
}
})
task.resume()
}
EDIT:
Thanks!
Error -1004 is URLError.cannotConnectToHost. It cannot connect to the server for some reason.
In comments, you say the URL is http://127.0.0.1. That is localhost, the current machine. If you use that URL on a physical phone, it's going to look for the web server on the phone. Lol. It works on the simulator, because the simulator is your computer, the localhost.
You need a URL that your iPhone can resolve to the machine running your web service. For example, find out what the IP for the computer running the web service on your local network, make sure your iPhone is on wifi on the same network, and then use that unique IP number for your computer on the LAN (likely something more like 192.168.0.x).
I was getting the same problem when i was sending/ receiving socket messages! I am using Socket.io and Firebase for push and the error was at the node.js backend. The error was that the mongoose version was deprecated. Whenever this error arises at the iOS End, ask the node.js backend team to look for Red color crash logs. They will surely find the problem causing this error on frontend. Hope this helps !!
In my case i'm not changes the Local host IP address.
Example : #"http://Localhost/Host name/index.pnp/apiname?";
initially i'm used above URL, so i'm got the same error...
Later i changed in to Localhost to 190.177.0.22
Example : #"http://190.177.0.22/Host name/index.pnp/apiname?";
Another corner case if you using something like ngrok and it's still not working is the phone isn't connected to a service provider network or wifi.
In my case my main phone was working the second out of service phone was not.

Firebase Storage download to local file error

I'm trying to download the image f5bd8360.jpeg from my Firebase Storage.When I download this image to memory using dataWithMaxSize:completion, I'm able to download it.
My problem comes when I try to download the image to a local file using the writeToFile: instance method. I'm getting the following error:
Optional(Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown
error occurred, please check the server response."
UserInfo={object=images/f5bd8360.jpeg,
bucket=fir-test-3d9a6.appspot.com, NSLocalizedDescription=An unknown
error occurred, please check the server response.,
ResponseErrorDomain=NSCocoaErrorDomain, NSFilePath=/Documents/images,
NSUnderlyingError=0x1700562c0 {Error Domain=NSPOSIXErrorDomain Code=1
"Operation not permitted"}, ResponseErrorCode=513}"
Here is a snippet of my Swift code:
#IBAction func buttonClicked(_ sender: UIButton) {
// Get a reference to the storage service, using the default Firebase App
let storage = FIRStorage.storage()
// Get reference to the image on Firebase Storage
let imageRef = storage.reference(forURL: "gs://fir-test-3d9a6.appspot.com/images/f5bd8360.jpeg")
// Create local filesystem URL
let localURL: URL! = URL(string: "file:///Documents/images/f5bd8360.jpeg")
// Download to the local filesystem
let downloadTask = imageRef.write(toFile: localURL) { (URL, error) -> Void in
if (error != nil) {
print("Uh-oh, an error occurred!")
print(error)
} else {
print("Local file URL is returned")
}
}
}
I found another question with the same error I'm getting but it was never answered in full. I think the proposal is right. I don't have permissions to write in the file. However, I don't know how gain permissions. Any ideas?
The problem is that at the moment when you write this line:
let downloadTask = imageRef.write(toFile: localURL) { (URL, error) -> Void in
etc.
you don't yet have permission to write to that (localURL) location. To get the permission you need to write the following code before trying to write anything to localURL
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let localURL = documentsURL.appendingPathComponent("filename")
By doing it you will write the file into the following path on your device (if you are testing on the real device):
file:///var/mobile/Containers/Data/Application/XXXXXXXetc.etc./Documents/filename
If you are testing on the simulator, the path will obviously be somewhere on the computer.

Swift: downloadTaskWithURL sometimes "succeeds" with non-nil location even though file does not exist

The downloadTaskWithURL function sometimes returns a non-nil location for a file that does not exist.
There is no file at http://192.168.0.102:3000/p/1461224691.mp4 in the test environment.
Most of the time, invoking downloadTaskWithURL on this URL results in the expected error message:
Error downloading message during network operation. Download URL:
http://192.168.0.102:3000/p/1461224691.mp4. Location: nil. Error:
Optional(Error Domain=NSURLErrorDomain Code=-1100 "The requested URL
was not found on this server." UserInfo=0x17547b640
{NSErrorFailingURLKey=http://192.168.0.102:3000/p/1461224691.mp4,
NSLocalizedDescription=The requested URL was not found on this
server.,
NSErrorFailingURLStringKey=http://192.168.0.102:3000/p/1461224691.mp4})
Occasionally, and in a non-deterministic way, downloadTaskWithURL believes the file exists and writes something to the location variable. As a result, the guard condition does not fail, and the code continues to execute ... which it should not.
The permanent file created by fileManager.moveItemAtURL(location!, toURL: fileURL) is only 1 byte, confirming that the network file never existed in the first place.
Why does downloadTaskWithURL behave like this?
func download() {
// Verify <networkURL>
guard let downloadURL = NSURL(string: networkURL) where !networkURL.isEmpty else {
print("Error downloading message: invalid download URL. URL: \(networkURL)")
return
}
// Generate filename for storing locally
let suffix = (networkURL as NSString).pathExtension
let localFilename = getUniqueFilename("." + suffix)
// Create download request
let task = NSURLSession.sharedSession().downloadTaskWithURL(downloadURL) { location, response, error in
guard location != nil && error == nil else {
print("Error downloading message during network operation. Download URL: \(downloadURL). Location: \(location). Error: \(error)")
return
}
// If here, no errors so save message to permanent location
let fileManager = NSFileManager.defaultManager()
do {
let documents = try fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let fileURL = documents.URLByAppendingPathComponent(localFilename)
try fileManager.moveItemAtURL(location!, toURL: fileURL)
self.doFileDownloaded(fileURL, localFilename: localFilename)
print("Downloaded file # \(localFilename). Download URL: \(downloadURL)")
} catch {
print("Error downloading message during save operation. Network URL: \(self.networkURL). Filename: \(localFilename). Error: \(error)")
}
}
// Start download
print("Starting download # \(downloadURL)")
task.resume()
}
Just to clarify, the server is returning a 404, but the download task is returning a basically-empty file? And you're certain that the server actually returned an error code (by verifying the server logs)?
Either way, I would suggest checking the status code in the response object. If it isn't a 200, then the download task probably just downloaded the response body of an error page. Or, if the status code is 0, the connection timed out. Either way, treat it as a failure.
You might also try forcing this to all happen on a single thread and see if the nondeterminism goes away.

Resources