user25931: I'm using ESP8266 Arduino for compiling and uploading my code to NodeMCU 1.0 (ESP-12E Module).
Flash Size: 4M (3M SPIFFS)
CPU frequency: 80 MHz
Upload Speed: 115200
I'm using portable arduino-1.6.9-windows extracted in my D: drive. I'm using the latest ESP8266 Arduino image brought by git command.
I've written this basic code to download 'datalog.txt' file (stored in the root of my SD card).
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

const char *ssid = "tiny-esp";
const char *password = "password";

ESP8266WebServer server(80);

String home = "<h1>Hello! from ESP8266!</h1>"
                "<p><a href=\"down\"><button>Download</button></a>";

void handleRoot() {
    server.send(200, "text/html", home);
}

void handleDownload() {

    File dataFile = SD.open("datalog.txt");
    int fsizeDisk = dataFile.size();
    Serial.print("fsizeDisk: ");
    Serial.println(fsizeDisk);

    size_t fsizeSent = server.streamFile(dataFile,"text/plain");

    Serial.print("fsizeSent: ");
    Serial.println(fsizeSent);

    dataFile.close();
}


void setup() {
    delay(500);
    Serial.begin(115200);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("Please visit: \n");
    Serial.println(apip);

    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
        Serial.println("\nCard failed, or not present");
        // don't do anything more:
        return;
    }
    Serial.println("\nCard Initialized.");

    server.on("/", handleRoot);
    server.on("/down", handleDownload);
    server.begin();
    Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}

But, when I press the 'Download' button, the ESP hangs, dumps some errors and then restarts as displayed below (from my Serial Monitor):
Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600

Panic D:\arduino-1.6.9-windows\arduino-1.6.9\hardware\esp8266com\esp8266\cores\esp8266\core_esp8266_main.cpp:98 __yield

ctx: sys 
sp: 3ffffc80 end: 3fffffb0 offset: 01b0

>>>stack>>>
3ffffe30:  3ffefdf4 000003b9 000003b9 4010020c  
3ffffe40:  00000000 3ffe9645 00000001 4020815d  
3ffffe50:  3ffefdf4 00000481 3fff0d50 402077e5  
3ffffe60:  3fff337c 00000b68 00000000 40207823  
3ffffe70:  3fff3a74 3fff1480 3fff3a74 3fff1474  
3ffffe80:  3fff337c 00000b68 3fff307c 40202a57  
3ffffe90:  3fff3a74 00000b68 3fff2cfc 40202c07  
3ffffea0:  00000000 3ffe9704 3fff337c 3fff1474  
3ffffeb0:  3fff337c 3fff147c 3fff2cfc 40202d34  
3ffffec0:  3ffeead0 0883f900 3fff1478 40202d54  
3ffffed0:  3fff337c 3fff147c 3fff1478 4022670d  
3ffffee0:  00000000 0104a8c0 00000010 00000000  
3ffffef0:  00000000 00000010 3ffefe40 40221001  
3fffff00:  40210000 00000000 0000007d 3fff151c  
3fffff10:  3ffebae4 3fff1520 3fff3434 40224b39  
3fffff20:  3fff1370 3fff1fac 3fff1fac 4021547e  
3fffff30:  40215972 3ffed310 3ffebabc 3fff1fac  
3fffff40:  3ffebad6 00000000 3fff3434 40223f35  
3fffff50:  0204a8c0 3ffee318 02a93dee 00000000  
3fffff60:  40104b62 02a93dee 3ffeead0 60000600  
3fffff70:  4022d230 3ffeeaa8 3ffeead0 0884220c  
3fffff80:  4022d256 3fffdab0 00000000 3fff2004  
3fffff90:  3fffdc90 00000000 3fff3434 4022ce8b  
3fffffa0:  40000f49 3fffdab0 3fffdab0 40000f49  
<<<stack<<<

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v00000000
~ld

Please visit: 
192.168.4.1

Card Initialized.
HTTP server started

I tried updating the code by writing custom "server.streamFile()" function and adding
"Content-Disposition: attachment; filename=\"datalog.txt\"\r\n";

to the header to allow downloading the txt file as an attachment.
The modified code is [Only handleDownload() function has been changed]:
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <SPI.h>
#include <SD.h>

const int chipSelect = 4;

const char *ssid = "tiny-esp";
const char *password = "password";

ESP8266WebServer server(80);

String home = "<h1>Hello! from ESP8266!</h1>"
                "<p><a href=\"down\"><button>Download</button></a>";

void handleRoot() {
    server.send(200, "text/html", home);
}

void handleDownload() {

    int32_t time = millis();
    File dataFile = SD.open("datalog.txt");
    int fsizeDisk = dataFile.size();
    Serial.print("fsizeDisk: "); Serial.println(fsizeDisk);

    String WebString = "";
    WebString += "HTTP/1.1 200 OK\r\n";
    WebString += "Content-Type: text/plain\r\n";
    WebString += "Content-Disposition: attachment; filename=\"datalog.txt\"\r\n";
    WebString += "Content-Length: " + String(fsizeDisk) + "\r\n";
    WebString += "\r\n";
    server.sendContent(WebString);

    char buf[1024];
    int siz = dataFile.size();
    while(siz > 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        dataFile.read((uint8_t *)buf, len);
        server.client().write((const char*)buf, len);
        siz -= len;
    }
    Serial.print(siz);
    Serial.println(" Bytes left!");

    dataFile.close();
    time = millis() - time;
    Serial.print(time); Serial.println(" ms elapsed");
}


void setup() {
    delay(500);
    Serial.begin(115200);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("Please visit: \n");
    Serial.println(apip);

    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
        Serial.println("\nCard failed, or not present");
        // don't do anything more:
        return;
    }
    Serial.println("\nCard Initialized.");

    server.on("/", handleRoot);
    server.on("/down", handleDownload);
    server.begin();
    Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}

Now, when I press the Download button, a popup opens up in browser displaying "datalog.txt" has started downloading. But after about 20-30 seconds it says "Download failed". The esp freezes after printing the 'fsizeDisk'.
Meanwhile, the serial monitor reads:
Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600

I don't understand what am I doing wrong. Please help!
EDIT: I added delay(2) and a Serial.println(cnt++) inside while(siz > 0) in handleDownload() for debugging:
int cnt=1;
delay(10);
while(siz > 0) {
    delay(2);
    Serial.println(cnt++);
    size_t len = std::min((int)(sizeof(buf) - 1), siz);
    dataFile.read((uint8_t *)buf, len);
    server.client().write((const char*)buf, len);
    siz -= len;
}

What happens now is, I get 
Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600
1
2
3
4
5
6
7
8

The loop may hang up at any count(e.g. 10, 15, 17, 23, etc). Also, in my browser, it reads as 28% downloaded (for cnt=8) or so. So, file starts downloading but hangs up midway. I've tried increasing the delay upto 10 ms, but there has been no progress.

user28828: try to add a yield() command in to your wihle-loop.
With yield() the ESP hast time to do his background jobs.

25931: <p>I'm using ESP8266 Arduino for compiling and uploading my code to NodeMCU 1.0 (ESP-12E Module).
Flash Size: 4M (3M SPIFFS)
CPU frequency: 80 MHz
Upload Speed: 115200</p>

<p>I'm using portable arduino-1.6.9-windows extracted in my D: drive. I'm using the latest ESP8266 Arduino image <a href="https://github.com/esp8266/Arduino#using-git-version" rel="nofollow noreferrer">brought by git command</a>.</p>

<p>I've written this basic code to download 'datalog.txt' file (stored in the root of my SD card).</p>

<pre><code>#include &lt;ESP8266WiFi.h&gt;
#include &lt;WiFiClient.h&gt; 
#include &lt;ESP8266WebServer.h&gt;
#include &lt;SPI.h&gt;
#include &lt;SD.h&gt;

const int chipSelect = 4;

const char *ssid = "tiny-esp";
const char *password = "password";

ESP8266WebServer server(80);

String home = "&lt;h1&gt;Hello! from ESP8266!&lt;/h1&gt;"
                "&lt;p&gt;&lt;a href=\"down\"&gt;&lt;button&gt;Download&lt;/button&gt;&lt;/a&gt;";

void handleRoot() {
    server.send(200, "text/html", home);
}

void handleDownload() {

    File dataFile = SD.open("datalog.txt");
    int fsizeDisk = dataFile.size();
    Serial.print("fsizeDisk: ");
    Serial.println(fsizeDisk);

    size_t fsizeSent = server.streamFile(dataFile,"text/plain");

    Serial.print("fsizeSent: ");
    Serial.println(fsizeSent);

    dataFile.close();
}


void setup() {
    delay(500);
    Serial.begin(115200);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("Please visit: \n");
    Serial.println(apip);

    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
        Serial.println("\nCard failed, or not present");
        // don't do anything more:
        return;
    }
    Serial.println("\nCard Initialized.");

    server.on("/", handleRoot);
    server.on("/down", handleDownload);
    server.begin();
    Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}
</code></pre>

<p>But, when I press the 'Download' button, the ESP hangs, dumps some errors and then restarts as displayed below (from my Serial Monitor):</p>

<pre><code>Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600

Panic D:\arduino-1.6.9-windows\arduino-1.6.9\hardware\esp8266com\esp8266\cores\esp8266\core_esp8266_main.cpp:98 __yield

ctx: sys 
sp: 3ffffc80 end: 3fffffb0 offset: 01b0

&gt;&gt;&gt;stack&gt;&gt;&gt;
3ffffe30:  3ffefdf4 000003b9 000003b9 4010020c  
3ffffe40:  00000000 3ffe9645 00000001 4020815d  
3ffffe50:  3ffefdf4 00000481 3fff0d50 402077e5  
3ffffe60:  3fff337c 00000b68 00000000 40207823  
3ffffe70:  3fff3a74 3fff1480 3fff3a74 3fff1474  
3ffffe80:  3fff337c 00000b68 3fff307c 40202a57  
3ffffe90:  3fff3a74 00000b68 3fff2cfc 40202c07  
3ffffea0:  00000000 3ffe9704 3fff337c 3fff1474  
3ffffeb0:  3fff337c 3fff147c 3fff2cfc 40202d34  
3ffffec0:  3ffeead0 0883f900 3fff1478 40202d54  
3ffffed0:  3fff337c 3fff147c 3fff1478 4022670d  
3ffffee0:  00000000 0104a8c0 00000010 00000000  
3ffffef0:  00000000 00000010 3ffefe40 40221001  
3fffff00:  40210000 00000000 0000007d 3fff151c  
3fffff10:  3ffebae4 3fff1520 3fff3434 40224b39  
3fffff20:  3fff1370 3fff1fac 3fff1fac 4021547e  
3fffff30:  40215972 3ffed310 3ffebabc 3fff1fac  
3fffff40:  3ffebad6 00000000 3fff3434 40223f35  
3fffff50:  0204a8c0 3ffee318 02a93dee 00000000  
3fffff60:  40104b62 02a93dee 3ffeead0 60000600  
3fffff70:  4022d230 3ffeeaa8 3ffeead0 0884220c  
3fffff80:  4022d256 3fffdab0 00000000 3fff2004  
3fffff90:  3fffdc90 00000000 3fff3434 4022ce8b  
3fffffa0:  40000f49 3fffdab0 3fffdab0 40000f49  
&lt;&lt;&lt;stack&lt;&lt;&lt;

 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v00000000
~ld

Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
</code></pre>

<p>I tried updating the code by writing custom "server.streamFile()" function and adding</p>

<pre><code>"Content-Disposition: attachment; filename=\"datalog.txt\"\r\n";
</code></pre>

<p>to the header to allow downloading the txt file as an attachment.</p>

<p>The modified code is [Only handleDownload() function has been changed]:</p>

<pre><code>#include &lt;ESP8266WiFi.h&gt;
#include &lt;WiFiClient.h&gt; 
#include &lt;ESP8266WebServer.h&gt;
#include &lt;SPI.h&gt;
#include &lt;SD.h&gt;

const int chipSelect = 4;

const char *ssid = "tiny-esp";
const char *password = "password";

ESP8266WebServer server(80);

String home = "&lt;h1&gt;Hello! from ESP8266!&lt;/h1&gt;"
                "&lt;p&gt;&lt;a href=\"down\"&gt;&lt;button&gt;Download&lt;/button&gt;&lt;/a&gt;";

void handleRoot() {
    server.send(200, "text/html", home);
}

void handleDownload() {

    int32_t time = millis();
    File dataFile = SD.open("datalog.txt");
    int fsizeDisk = dataFile.size();
    Serial.print("fsizeDisk: "); Serial.println(fsizeDisk);

    String WebString = "";
    WebString += "HTTP/1.1 200 OK\r\n";
    WebString += "Content-Type: text/plain\r\n";
    WebString += "Content-Disposition: attachment; filename=\"datalog.txt\"\r\n";
    WebString += "Content-Length: " + String(fsizeDisk) + "\r\n";
    WebString += "\r\n";
    server.sendContent(WebString);

    char buf[1024];
    int siz = dataFile.size();
    while(siz &gt; 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        dataFile.read((uint8_t *)buf, len);
        server.client().write((const char*)buf, len);
        siz -= len;
    }
    Serial.print(siz);
    Serial.println(" Bytes left!");

    dataFile.close();
    time = millis() - time;
    Serial.print(time); Serial.println(" ms elapsed");
}


void setup() {
    delay(500);
    Serial.begin(115200);
    Serial.println();

    WiFi.softAP(ssid, password);

    IPAddress apip = WiFi.softAPIP();
    Serial.print("Please visit: \n");
    Serial.println(apip);

    // see if the card is present and can be initialized:
    if (!SD.begin(chipSelect)) {
        Serial.println("\nCard failed, or not present");
        // don't do anything more:
        return;
    }
    Serial.println("\nCard Initialized.");

    server.on("/", handleRoot);
    server.on("/down", handleDownload);
    server.begin();
    Serial.println("HTTP server started");
}

void loop() {
    server.handleClient();
}
</code></pre>

<p>Now, when I press the Download button, a popup opens up in browser displaying "datalog.txt" has started downloading. But after about 20-30 seconds it says "Download failed". The esp freezes after printing the 'fsizeDisk'.</p>

<p>Meanwhile, the serial monitor reads:</p>

<pre><code>Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600
</code></pre>

<p>I don't understand what am I doing wrong. Please help!</p>

<p><strong>EDIT:</strong> I added delay(2) and a Serial.println(cnt++) inside <em>while(siz > 0)</em> in handleDownload() for debugging:</p>

<pre><code>int cnt=1;
delay(10);
while(siz &gt; 0) {
    delay(2);
    Serial.println(cnt++);
    size_t len = std::min((int)(sizeof(buf) - 1), siz);
    dataFile.read((uint8_t *)buf, len);
    server.client().write((const char*)buf, len);
    siz -= len;
}
</code></pre>

<p>What happens now is, I get </p>

<pre><code>Please visit: 
192.168.4.1

Card Initialized.
HTTP server started
fsizeDisk: 28600
1
2
3
4
5
6
7
8
</code></pre>

<p>The loop may hang up at any count(e.g. 10, 15, 17, 23, etc). Also, in my browser, it reads as 28% downloaded (for cnt=8) or so. So, file starts downloading but hangs up midway. I've tried increasing the delay upto 10 ms, but there has been no progress.</p>
 28828: <p>try to add a yield() command in to your wihle-loop.
With yield() the ESP hast time to do his background jobs.</p>
