Easily transfer the contents of any directory from your Mac to your mobile using Python and an automatically generated QR code. Readily available as a Bash script on GitHub.

Transferring Files Between Devices

From time to time, I find myself needing to transfer files between devices, mostly from my Mac to my Android phone. As this transfer crosses system and platform boundaries, native solutions can be a bit sparse and sometimes a little creativity is required.

Wires?

Like most older Android phones, mine also shipped with a Type A USB charging cable. It's good for charging as well as data transfers.

However, the origin of the data being a Mac, makes things a bit more complicated. Modern Macs no longer ship with Type A USB ports but rather with Type C USB ports. Mine is no exception.

Plus, once you've shelled out the extra cash to buy a USB hub and eventually plugged it in, you find yourself still needing an extra piece of software, as the two devices do not seem to be able to natively talk to each other.

Apart from the technical complications above, I can't seem to find the right cable half of the time anyways. So, why not go wireless after all?!

Bluetooth?

If the files to be transferred are small enough, Bluetooth usually does a fairly decent job. Once the file sizes venture beyond a certain threshold, say anything above 50 MiB, Bluetooth really is no longer a viable option; it just takes ages to transfer the files in my case.

So, again something else is needed. A different, but also a proven technology.

WiFi!

The recent advancements in WiFi technology, especially around the 11n and 11ac generation, generally make it a rather compelling option. Transfer speeds of 10 MiB per second and more are now standard in most homes.

This speed allows to transfer gigabytes of data in an mere matter of seconds or minutes (depending on size, throughput, interference, etc.). But which protocol to use? What about one that the whole world seems to use nowadays? HTTP.

The Quest for a Simple Web Server

This leaves the question of how to spin up an HTTP web server. A quick search on the search engine of choice reveals that they are probably more web server frameworks than atoms in the universe (logical pun intended), nginx being amongst the most popular one.

However, fully fledged web servers tend to be non-trivial to configure and operate. Simply because security really matters when it comes to web servers. You want your web server to serve your content and not the contents of someone who happened to hijack it.

Python — Batteries Included!

But what about simply serving a bunch of files in your local network for a very short period of time so that other devices can access or download them? Once complete, simply shut down the web server and carry on as if nothing had happened.

Sure, you can still utilise a fully fledged web server for the task at hand but there are simpler alternatives, especially if you already have Python installed.

Every recent installation actually ships with a simple web server by default that can be started with a single command from a terminal. For Python2, the magic command is

python -m SimpleHTTPServer

and for Python3, the magic command is

python3 -m http.server

When accessed from a web browser, the result looks something like the following screenshot, assuming the local machine has IP address 192.168.1.173.

Example Directory Listing

The Python module does what it says on the tin — it starts a web server and then serves a listing of the current directory. Some may argue that it's not the most stylish representation but it sure is practical. Especially when it comes to accessing or downloading files.

However, there is a slight problem. While the Python command is excellent for spinning up a web server on your local computer it is not that easily accessible from any mobile device in your network.

QR Codes to the Rescue!

You need to know the IP address and then punch that IP address alongside the corresponding port number into your mobile device for access. And if you've ever typed something like http://192.168.1.173:8000 into a browser on your mobile then you know that this can be a tedious task. There has to be a better way! And there is.

The solution comes in the form of two-dimensional barcodes, called QR codes. They can be used to hold any information; in this case the URL of the web server. The example code below holds the address of the web server at http://192.168.1.173:8000.

Example Web Server URL

Feel free to scan the code on your mobile and open up the link in a browser. Unless you also have a web server running on http://192.168.1.173:8000 there will be nothing to show for, but you get the idea. Your mobile recognised the QR code, read and decoded the information in it, and opened up a browser window pointed at the corresponding URL.

Putting it All Together

While the above QR code solves the problem for a single static IP address and port, it does not yet solve the problem in general. However, we can combine the simplicity of the Python web server and the power of the QR code in a single Bash script.

This is exactly what Bash script web-serve-this-directory.sh in GitHub repository https://github.com/dumrauf/web_serve_this_directory was set out to achieve.

Given an available port, spin up a Python web server, generate a QR code containing the URL of the web server, and make the QR code accessible through the web server. Once done, the Bash script cleans up after itself, so that QR codes do not keep piling up.

When visiting the web server, the familiar directory listing is displayed as shown below.

Example Directory Listing With QR Code

Note that the directory listing now includes the additional webserver_url.jpg image. Clicking it displays the QR code as shown below.

Example QR Code

This allows to easily access the contents of the web server from any mobile device in the local network.

Web-Serve-This-Directory

The repository https://github.com/dumrauf/web_serve_this_directory contains a Bash script that starts a Python web server with the current directory at its root.

In case qrencode can be detected, a QR code with the URL of the web server is also created. When scanning the QR code on a phone or tablet connected to the same network, it allows instant access to the local machine. This can save a lot of typing.

Warning: This web server is great for quick and dirty experimentation in a development environment. DO NOT use this web server in a production environment! It is unsuitable for the task, does not scale well, and there are better options available. Instead choose one of the battle tested web server such as nginx.

You Have

Before you can use the Bash script in this repository out of the box, you need

  • a Python installation, either Python2 or Python3
  • an available port for the web server to listen on

Optionally, install qrencode if you want to automatically generate a QR codes for the web server URL each time it starts.

You Want

After running the Bash script in this repository you can access the contents of the current directory from any device in the same network over HTTP.

Execution

The stand-alone Bash script web-serve-this-directory.sh is located in the root folder of the repository.

Starting the Web Server

The current directory can be served over HTTP on port 8000 via

./web-serve-this-directory.sh -p 8000

In case the local IP address is 192.168.1.162, this will start the web server and produce the following output

$ ./web-serve-this-directory.sh -p 8000
Visit http://192.168.1.162:8000 from your mobile to download files in this directory.
Scan http://192.168.1.162:8000/webserver_url.jpg with your mobile for quicker access
Press Ctrl-C to stop the web sever
Serving HTTP on 0.0.0.0 port 8000 ...

Note that since qr_encode could be detected, a QR code has been generated and can be accessed on http://192.168.1.162:8000/webserver_url.jpg.

Stopping the Web Server

The web server can be stopped by pressing Ctrl-C; this is actually standard Python web server behaviour. The full output for the above example on Python2 is

$ ./web-serve-this-directory.sh -p 8000
Visit http://192.168.1.162:8000 from your mobile to download files in this directory.
Scan http://192.168.1.162:8000/webserver_url.jpg with your mobile for quicker access
Press Ctrl-C to stop the web sever
Serving HTTP on 0.0.0.0 port 8000 ...
^CTraceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 162, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SimpleHTTPServer.py", line 235, in <module>
    test()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SimpleHTTPServer.py", line 231, in test
    BaseHTTPServer.test(HandlerClass, ServerClass)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/BaseHTTPServer.py", line 599, in test
    httpd.serve_forever()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 236, in serve_forever
    poll_interval)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 155, in _eintr_retry
    return func(*args)
KeyboardInterrupt
$ 

Note that the KeyboardInterrupt error is expected. Ctrl-C was pressed after all - which qualifies as a KeyboardInterrupt.

FAQs

Below is a list of frequently asked questions.

Why is there no HTTPS Support?

The server is intended to be a simple lightweight way to serve files on a local network. It should not be used to transfer sensitive files. However, it seems to be possible to add HTTPS support. Feel free to improve as outlined below, so we can make things better for everyone.

Does the World Really Need Yet Another 100+ Line Bash Script to Start a Simple Python Web Server?

Probably not.

But then accessing the web server from any mobile in the same network by simply scanning a QR code included in the web server makes it that much easier. Plus, the script cleans up after itself. Which is a bonus. Who want tons of QR codes littering up directories?

Sometimes, convenience is king.

I Know How to Make This Better!

Excellent. Feel free to fork the repository, make the changes in your fork, and open a pull request so we can make things better for everyone. Thanks!

Conclusion

The web-serve-this-directory.sh Bash script introduced above makes it easy for me to temporarily access the contents of any directory on my Mac from any mobile device in the local network by merely scanning a QR code.

While this works for me, it may be different in your case. Feel free to leave a comment or contribute to the Git repository, so we can make things better for everyone. Thanks!