Use of favicon.ico with webserver

Webserver I am using receives Two GET requests for “favicon.ico” each time I goto webpage home with a newly opened browser (FF). After these two instances I no longer see GET request for “favicon.ico.”

This can be observed in the attached file: favicon.jpg

Including a section of code where I attempt to handle the GET request for “Favicon.ico.” I plan to put the do-while download loop in to a function; as it gets used repeatedly; mostly for large files.

// Check the action to see if it was a GET request.
						if ((strcmp(action, "GET") == 0) && (strcmp(path, "/favicon.ico") == 0))  // Respond with the path that was accessed. 
						{
											
							// Open file for reading
							SdFile webFile;
								webFile.open("favicon.ico", O_READ);
							if (!webFile.isOpen()) error("log");
																			
								fileDownload = 1;   //File download has started
								
									// send a standard http response header
									client.println("HTTP/1.1 200 OK");
									client.println("Content-Type: 'image/ico'");
									client.println();
									client.println("<!DOCTYPE HTML><head>");
									client.println("<html>\r\n");
									client.println("<body>\r\n");
									client.println("<link rel='icon' type='image/ico' href='http://192.168.1.71:7388/favicon.ico'/></head>");
									//client.println("<link rel='icon' href='http://192.168.1.71:7388/favicon.ico' type='image/x-icon'></head>");
									
										
										do   // @ adafruit_support_rick's do-while loop
										{
											int count = 0;
											char buffers[BUFSIZE];
											bool done = false;
											while ((!done) && (count < BUFSIZE) && (webFile.available()))
											{
											  char c = webFile.read();
											  if (0 > c)
												done = true;
											  else
												buffers[count++] = c;
												delayMicroseconds(1000);
											}
											if (count)
											client.write( buffers, count);
											
										} while (webFile.available());
									
									client.println("<body />\r\n");
									client.println("
\r\n");
									client.println("</html>\r\n");
									
							//
							webFile.close();
							
							fileDownload = 0;  //File download has finished
							
							//Serial.println("webFile Closed");
							Serial.flush();

								
							exit;
									
							 
										
						
						}

Will there always be two GET Requests for “favicon.co?”

William

That depends on the web browser. Some request it every time. Some request it only once per session.

Tim,

Thank you for all the time you spend helping people on this forum!

Do you see anything wrong in my approach to returning the "favicon.ico"? I am not seeing the "favicon.ico" show up. FF Browser has the outline of a square box in the bookmark toolbar. There is no "favicon.ico" to the left of the web page "title."

William

I have a well tested example server sketch in the playground that handles several types of file downloads from the SD card, including favicon.ico. Maybe you can use parts of it for your code.
http://playground.arduino.cc/Code/WebServerST

Does your favicon.ico meet the design requirements (if any) for an icon file?

@ SurferTim

Will try http://playground.arduino.cc/Code/WebServerST approach.

@ zoomkat

Thank you for all the time you spend helping here on the forum.

I used one of the "favicon.ico" generators. Do you have a "favicon.ico" generator you could recommend?

I would think one of these generators would meet design requirements.

William

Do you have a “favicon.ico” generator you could recommend?

I usually ignore client request and close the client connection if there is nothing in the request of interest, which includes icon request. I may have seen in the past a graphic file included in the arduino code which may have been an .ico file. Probably easiest to serve from an SD card.

Here is what happens: Open Firefox browser, go to server "Weather" page. Pulls up "Weather" page, followed by two "Get" requests for "favicon.ico." If I leave Firefox browser open, then go to one of two pages, only the request for that web page shows in the Serial Monitor. If I close FF, and go to one of two server web pages, I am back to getting two "GET" requests for "favicon.ico." Again, I can leave FF open --I only see the "GET" request for server web page.

Here is a link to video of my project and "favicon.ico" behavior:

http://tinyurl.com/os4498k Google Drive share.

One can see in the video; after the "favicon.ico" is closed quickly.

I used this site to create the "favicon.ico" I am using and serving from SD card:

William

William

Firefox should make only one request for the favicon file every session. However, the newest release is requesting the favicon.ico file twice per file request.

If I go to a different page, I get another two favicon requests for that page also. If I use the "back" icon on the browser, I get another favicon request, but not a request for the page itself.

Sounds like Firefox has a minor bug there.

edit: Despite the Firefox bug, my server code sends the favicon.ico file every time it is requested.

@ SurferTim

Your WebserverST; is this the section that handles sending the correct file type? Is this enough for a standalone function or is there more to this section code?

 strcpy_P(tBuf,PSTR("HTTP/1.0 200 OK\r\nContent-Type: "));

                // send Content-Type
                if(strcmp(fileType,"HTM") == 0) strcat_P(tBuf,PSTR("text/html"));
                else if(strcmp(fileType,"PHP") == 0) strcat_P(tBuf,PSTR("text/html"));
                else if(strcmp(fileType,"TXT") == 0) strcat_P(tBuf,PSTR("text/plain"));
                else if(strcmp(fileType,"CSS") == 0) strcat_P(tBuf,PSTR("text/css"));
                else if(strcmp(fileType,"GIF") == 0) strcat_P(tBuf,PSTR("image/gif"));
                else if(strcmp(fileType,"JPG") == 0) strcat_P(tBuf,PSTR("image/jpeg"));
                else if(strcmp(fileType,"JS") == 0) strcat_P(tBuf,PSTR("application/javascript"));
                else if(strcmp(fileType,"ICO") == 0) strcat_P(tBuf,PSTR("image/x-icon"));
                else if(strcmp(fileType,"PNG") == 0) strcat_P(tBuf,PSTR("image/png"));
                else if(strcmp(fileType,"PDF") == 0) strcat_P(tBuf,PSTR("application/pdf"));
                else if(strcmp(fileType,"ZIP") == 0) strcat_P(tBuf,PSTR("application/zip"));
                else strcat_P(tBuf,PSTR("text/plain"));

                strcat_P(tBuf,PSTR("\r\nConnection: close\r\n\r\n"));
                client.write(tBuf);

Please, could you explain this section of code?

William

The only purpose is to send the web browser the correct file type. If you don't use some of those, you can remove them to save program memory.

This is the line that is for the favicon.ico file.

   else if(strcmp(fileType,"ICO") == 0) strcat_P(tBuf,PSTR("image/x-icon"));

Are "strcat_P" and "PSTR" part of a library; I am not familiar with there meaning and how they are used.

William

They are part of the avr-gcc library. The client.print and client.println functions will send one character per packet if you use the F() function. This allows me to send that character array in one packet. Much faster send.

If a the F() macro is not being used and a tcp/ip packet is generated when the print function is executed, then the below might be all that is needed.

client.println("Content-Type: image/x-icon");

@ zoomkat

client.println(“Content-Type: image/x-icon”);

I think this is working; at least the two requests have gone away (for favicon.ico.) All I see in FF address bar is “hollow” icon where I expect to see my favicon.ico and there is nothing showing except the title of the web page on the browser tab “Weather Observations”.

Attaching a section of code from my project --for the “Weather” page; which is a dynamic web page displaying: date, time, humidity, temperature, and barometric pressure.

Second file “favico-request.txt” is where I handle the “GET” request.

Third file is the “Hollow” favicon.ico; output of the “Weather” page in Firefox browser.

William

Weather.txt (4.18 KB)

favico-request.txt (1.18 KB)

favicon.ico needs to be an ico file, not a text file. It is a graphic image.

Choice of file name for for uploaded file could have been better! This is not the actual favicon.ico image file; this is only a text file of a section of code I uploaded.

William

Hi

On my Arduino website at http://www.2wg.co.nz/2WG/ I process all icon requests including favicon.ico.

I use two standard icon files on the system's SD card - PUBLIC/LOC_ICON.PNG and PUBLIC/WWW_ICON.PNG for responding to local area network (me) and www (public) icon requests.

I only respond to two consecutive icon requests for any IP address and then ignore additional requests. If a user comes back later their browser will get served two more icon requests again.

This code translates any icon file request into a request to serve up the appropriate icon file as above:

  if (l_req_line.indexOf(EPSR(E_icon_50)) != -1) {
    //We may trim the leading and trailing slashes later
    if ((G_RemoteIPAddress[0] == 192) && (G_RemoteIPAddress[1] == 168)) 
      l_request_str = EPSR(E_slIMAGESslLOC_ICONdtPNGsl_249); // /IMAGES/LOC_ICON.PNG
    else
      l_request_str = EPSR(E_slIMAGESslWWW_ICONdtPNG_251);   // /IMAGES/WWW_ICON.PNG
    //
  }

I confirm that when responding to icon html requests I need to select/define/output the correct html content type before I open the file and dump/transmit its content to the ethernetclient object using print() statements.

If you access my website you should see my application icons pop up into your browser tabs and shortcuts.

Cheers

Catweazle NZ.

@ CatWeazleNZ

Thank you for taking time to comment on the problem I am having with "favicon.ico."

I have visited your web server; excellent work, much more advanced than my web server! Which Arduino are you using for your web server?

Could I be dealing with an old cached "favicon.ico?" I see the GET request and I see the file opened; but no where in Firefox 39.0 browser do I see the newly created "favicon.ico," what I do see where the favicon.ico" would be is a dotted, square outline, that is blank!

William

Techno500:
@ CatWeazleNZ

Thank you for taking time to comment on the problem I am having with “favicon.ico.”

I have visited your web server; excellent work, much more advanced than my web server! Which Arduino are you using for your web server?

Could I be dealing with an old cached “favicon.ico?” I see the GET request and I see the file opened; but no where in Firefox 39.0 browser do I see the newly created “favicon.ico,” what I do see where the favicon.ico" would be is a dotted, square outline, that is blank!

William

favicon.ico is just a common name for favourite icons - there are other names that browsers request as icon files including a few variants used by Apple IOS.

My application responds to any html request that includes “ICON” in the request by sending back one of two standard PNG icon files. My browsers (Firefox, Safari, IE, Opera) will scale the PNG files according to their needs. As an external user you should get back my blue PNG icon file.

Because my application only processes the first two sequential icon requests from an IP address a browser may not register the icon because the icon request it might want to register is its 3rd or 4th icon request.

When a web server responds to an icon request it does not return a filename (so hence the local file does not have to be favicon.ico). The web server just sets the html response content type, content length and then sends the file content. The browser should interpret the file content based on the content type value it receives and then utilise the image file, including scaling, according to its needs.

This is my code that sends files back to web browsers. There is lots of extraneous stuff but you should see the html response content type and content length being sent and the actual file being send to the browser using a 128 byte buffer.

void DumpFileToBrowser(char *p_filename) {
  //dump ROBOTS.TXT, JPG, PNG, INO, CPP, H, XLS, PDF, DOC files to browser
  const byte c_proc_num = 19;
  Push(c_proc_num);

  SPIDeviceSelect(DC_SDCardSSPin);
  if (!SD.exists(p_filename)) {
    StatisticCount(St_Direct_File_Hacks, true); //Exclude CWZ
    SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)

    SendHTMLResponse(EPSR(E_404_Not_Found_270), "", true); //response, content_type, blank line terminate
    G_EthernetClient.println(F("<!DOCTYPE HTML>"));
    G_EthernetClient.println(F("<html><body>"));
    G_EthernetClient.println(F("<b>File Not Found</b> "));
    G_EthernetClient.println(p_filename);
    G_EthernetClient.println(F("</body></html>"));
    Pop(c_proc_num);
    return;
  }
  SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)

  String l_content_type = EPSR(E_ContenthyTypeco__271);
  if (strstr(p_filename, ".TXT")) {
    StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_textslplain_272);
  }
  else if (strstr(p_filename, ".JPG")) {
    StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_imagesljpeg_273);
  }
  else if (strstr(p_filename, ".PNG")) {
    if (!strstr(p_filename, "ICON")) { //Don't count ICON requests
      StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    }
    l_content_type += EPSR(E_imageslpng_274);
  }
  else if (strstr(p_filename, ".INO")) {
    StatisticCount(St_Code_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_textslplain_272);
  }
  else if (strstr(p_filename, ".CPP")) {
    StatisticCount(St_Code_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_textslplain_272);
  }
  else if (strstr(p_filename, ".H")) {
    StatisticCount(St_Code_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_textslplain_272);
  }
  else if (strstr(p_filename, ".PDF")) {
    StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_applicationslpdf_275);
  }
  else if (strstr(p_filename, ".XLS")) {
    StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_applicationslvnddtmshyexcel_276);
  }
  else if (strstr(p_filename, ".DOC")) {
    StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    l_content_type += EPSR(E_applicationslmsword_277);
  }
  else {//D
    StatisticCount(St_Other_File_Downloads_E, true); //Exclude CWZ
    //l_content_type += "html/text";
    l_content_type += EPSR(E_textslplain_272);
  }
  //Don't blank line terminate because we need to add Content-Length: XXXX
  SendHTMLResponse(EPSR(E_200_OK_278), l_content_type, false); //response, content_type, blank line terminate

  //Open the SD card file
  SPIDeviceSelect(DC_SDCardSSPin);
  File l_file = SD.open(p_filename, FILE_READ);
  SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)

  if (!strstr(p_filename, ".TXT")) {
    //For images etc we write content length to the ethernet socket
    SPIDeviceSelect(DC_SDCardSSPin);
    unsigned long l_filesize = l_file.size();
    SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)
    G_EthernetClient.print(F("Content-Length: "));
    G_EthernetClient.println(l_filesize);
  }

  G_EthernetClient.println(); //DO NOT REMOVE OR WEB PAGES WILL NOT DISPLAY - HEADERS MUST END WITH A BLANK LINE

  //Now dump the file to the ethernetclient in buffered blocks
  //Consider bigger buffer size to see if we can get faster performance
  //Beware of running out of RAM
  const byte c_file_buffer_size = 128;
  byte l_buffer[c_file_buffer_size];
  int l_count = 0;
  int l_mod = 0;
  //if (strstr(p_filename,".TXT"))
  //  G_EthernetClient.println(F("<html><body><pre>"));
  //
  SPIDeviceSelect(DC_SDCardSSPin);
  while (l_file.available()) {
    l_count = l_file.read(l_buffer, c_file_buffer_size);
    if (l_count == 0)
      break;
    //
    SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)
    G_EthernetClient.write(l_buffer, l_count);
    l_mod++;
    if ((l_mod % 4) == 0) { //Only check every 512 chars (4 buffers)
      //This next line is used to terminate long www file download operations
      //when there is a local html file request operating
      if (Check4WaitingLocalHTMLReq()) {
        G_EthernetClient.println();
        G_EthernetClient.println("HTML Process Termination");
        break;
      }
    }
    SPIDeviceSelect(DC_SDCardSSPin);
  }
  SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)

  SPIDeviceSelect(DC_SDCardSSPin); //Enable Ethernet on SPI (Disable others)
  l_file.close();
  SPIDeviceSelect(DC_EthernetSSPin); //Enable Ethernet on SPI (Disable others)
  //if (strstr(p_filename,".TXT"))
  //  G_EthernetClient.println(F("</pre></body></html>"));
  //

  CheckRAM();
  Pop(c_proc_num);
} //

Cheers

Catweazle NZ