Homework 3: Image Uploads and
WebSockets
At this point, you have built a dynamic web application where users can login and chat with each other
using only a TCP socket, your understanding of web protocols, and your programming skills. This is a
great accomplishment, but let's take this further and allow users to upload images and interact in real
time.
Several changes have been made to the front end in the starter code repository. You should pull these
changes, or manually integrate them into your front end if you've customized your app. These changes
will be referenced throughout this assignment.
Repo: https://github.com/jessehartloff/WebAppProject
Learning Objective 1: Image Uploads
Allow authenticated users to upload an image as their profile picture. The uploaded image for a user will
replace the eagle image on the page.
A third HTML form has been added to the front end below the registration and login forms. This form is
designed to send an image to the path "/profile-pic" using the multipart/form-data encoding. Your task is:
1. Add an endpoint to your server that listens for requests at the path "/profile-pic"
2. Process the request based on whether or not the user is authenticated
a. If the request is from an authenticated user (based on a valid auth token):
i.
Parse the body of the request and extract the bytes of the image
ii.
Save this image as a file on your server
iii.
Store the filename of this image in your database as part of this user's profile
b. If the request is from an unauthenticated user, do not process the request and move on
to the next step
3. Respond with a 302 redirect to your home page "/"
a. If the user was authenticated, their profile picture should now be displayed on the home
page
When a user makes a request for your homepage, use HTML templating to send a page containing their
profile image where the eagle originally appeared. If the user is not logged in, or if they have not yet
uploaded a profile picture, you should display a default image (or no image) in this place on the page.
When an image is uploaded, your server will save the image as a file. It is recommended that you devise
a naming convention for the image files instead of using the names submitted by your users. Naming the
images "image1.jpg", "image2.jpg", "image3.jpg", etc is fine. Alternatively, since there is at most 1 image
per user, you can name them using the username for that image.
It is ok if your site only handles .jpg images and assumes that every file upload is a .jpg file.
Your uploads must persist through a server restart. You should store your images in files (It's generally
bad practice to store large files in a database), and store the filenames in your database. Since your
images are stored in files, they will already persist through a restart.
Note: You may need to set up your buffer to complete this objective depending on which
browser/version used during testing. Some browsers (Chrome) will send the headers of an HTTP
request before sending the body so you will only read the headers the first time you read from the TCP
socket. You need to read again to receive the bytes of the image. You can start by testing with very small
images to limit the amount of buffering to at most 2 reads from the socket in this objective. Later in this
assignment, you will expand this to arbitrarily large files. A very compressed image "elephant-small.jpg"
was added to the repo and can be used for testing.
Security: Don't allow the user to request arbitrary files on your server machine. Starting with this
objective, you will be hosting content at paths that cannot be hardcoded since you don’t know what
images will be uploaded to your site. Even if you replace the file names with your own naming
convention (eg. "image1.jpg" "image2.jpg") you still don't know how many images will be uploaded. This
means that you must accept some variable from the user that you will use to read, and send, a file from
your server. You must ensure that an attacker cannot use this variable to access files that you don’t want
them to access. (In this course, it is sufficient to not allow any '/' characters in the file path. Eg. remove
any "/" characters from the requested filename after extracting it from the path)
[Optional] Add the profile picture of the user who posted the message next to each message in the chat.
Testing Procedure
1. Start your server using docker compose up
2. Open a browser (Only use Firefox) and navigate to http://localhost:8080/
3. Use the image upload form to upload an image that is smaller than 1kb (Without logging in)
a. Verify that you are taken to the homepage through a redirect and that the default image is
still displayed
4. Register an account and login
5. Use the image upload form to upload an image that is smaller than 1kb
a. Verify that you are taken to the homepage through a redirect and that the uploaded image
is displayed
6. Open a second Firefox browser in incognito mode
7. Navigate to http://localhost:8080/ in the second browser
a. Verify that the default image appears
8. Register a second account and login
a. Verify that the default image still appears
9. Upload a second image that is smaller than 1kb
a. Verify that you are taken to the homepage through a redirect and that the uploaded image
is displayed
10. Go back to the first browser and refresh the page
a. Verify that first uploaded image still appears
11. Restart the server using docker compose restart
12. Refresh both browsers and verify that both images appear as expected for each user