Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / ffmpeg / libavformat / ftp.c
index dae8aa0..66c0665 100644 (file)
@@ -119,7 +119,7 @@ static int ftp_get_line(FTPContext *s, char *line, int line_size)
  */
 static int ftp_status(FTPContext *s, char **line, const int response_codes[])
 {
-    int err, i, dash = 0, result = 0, code_found = 0;
+    int err, i, dash = 0, result = 0, code_found = 0, linesize;
     char buf[CONTROL_BUFFER_SIZE];
     AVBPrint line_buffer;
 
@@ -135,25 +135,40 @@ static int ftp_status(FTPContext *s, char **line, const int response_codes[])
 
         av_log(s, AV_LOG_DEBUG, "%s\n", buf);
 
-        if (strlen(buf) < 4)
-            continue;
-
+        linesize = strlen(buf);
         err = 0;
-        for (i = 0; i < 3; ++i) {
-            if (buf[i] < '0' || buf[i] > '9')
-                continue;
-            err *= 10;
-            err += buf[i] - '0';
+        if (linesize >= 3) {
+            for (i = 0; i < 3; ++i) {
+                if (buf[i] < '0' || buf[i] > '9') {
+                    err = 0;
+                    break;
+                }
+                err *= 10;
+                err += buf[i] - '0';
+            }
         }
-        dash = !!(buf[3] == '-');
 
-        for (i = 0; response_codes[i]; ++i) {
-            if (err == response_codes[i]) {
-                if (line)
-                    av_bprintf(&line_buffer, "%s", buf);
+        if (!code_found) {
+            if (err >= 500) {
                 code_found = 1;
                 result = err;
-                break;
+            } else
+                for (i = 0; response_codes[i]; ++i) {
+                    if (err == response_codes[i]) {
+                        code_found = 1;
+                        result = err;
+                        break;
+                    }
+                }
+        }
+        if (code_found) {
+            if (line)
+                av_bprintf(&line_buffer, "%s\r\n", buf);
+            if (linesize >= 4) {
+                if (!dash && buf[3] == '-')
+                    dash = err;
+                else if (err == dash && buf[3] == ' ')
+                    dash = 0;
             }
         }
     }
@@ -198,8 +213,8 @@ static int ftp_auth(FTPContext *s)
     const char *user = NULL, *pass = NULL;
     char *end = NULL, buf[CONTROL_BUFFER_SIZE], credencials[CREDENTIALS_BUFFER_SIZE];
     int err;
-    static const int user_codes[] = {331, 230, 500, 530, 0}; /* 500, 530 are incorrect codes */
-    static const int pass_codes[] = {230, 503, 530, 0}; /* 503, 530 are incorrect codes */
+    static const int user_codes[] = {331, 230, 0};
+    static const int pass_codes[] = {230, 0};
 
     /* Authentication may be repeated, original string has to be saved */
     av_strlcpy(credencials, s->credencials, sizeof(credencials));
@@ -227,12 +242,54 @@ static int ftp_auth(FTPContext *s)
     return 0;
 }
 
+static int ftp_passive_mode_epsv(FTPContext *s)
+{
+    char *res = NULL, *start = NULL, *end = NULL;
+    int i;
+    static const char d = '|';
+    static const char *command = "EPSV\r\n";
+    static const int epsv_codes[] = {229, 0};
+
+    if (ftp_send_command(s, command, epsv_codes, &res) != 229 || !res)
+        goto fail;
+
+    for (i = 0; res[i]; ++i) {
+        if (res[i] == '(') {
+            start = res + i + 1;
+        } else if (res[i] == ')') {
+            end = res + i;
+            break;
+        }
+    }
+    if (!start || !end)
+        goto fail;
+
+    *end = '\0';
+    if (strlen(start) < 5)
+        goto fail;
+    if (start[0] != d || start[1] != d || start[2] != d || end[-1] != d)
+        goto fail;
+    start += 3;
+    end[-1] = '\0';
+
+    s->server_data_port = atoi(start);
+    av_dlog(s, "Server data port: %d\n", s->server_data_port);
+
+    av_free(res);
+    return 0;
+
+  fail:
+    av_free(res);
+    s->server_data_port = -1;
+    return AVERROR(ENOSYS);
+}
+
 static int ftp_passive_mode(FTPContext *s)
 {
     char *res = NULL, *start = NULL, *end = NULL;
     int i;
     static const char *command = "PASV\r\n";
-    static const int pasv_codes[] = {227, 501, 0}; /* 501 is incorrect code */
+    static const int pasv_codes[] = {227, 0};
 
     if (ftp_send_command(s, command, pasv_codes, &res) != 227 || !res)
         goto fail;
@@ -270,8 +327,6 @@ static int ftp_passive_mode(FTPContext *s)
   fail:
     av_free(res);
     s->server_data_port = -1;
-    av_log(s, AV_LOG_ERROR, "Set passive mode failed\n"
-                            "Your FTP server may use IPv6 which is not supported yet.\n");
     return AVERROR(EIO);
 }
 
@@ -317,7 +372,7 @@ static int ftp_file_size(FTPContext *s)
 {
     char command[CONTROL_BUFFER_SIZE];
     char *res = NULL;
-    static const int size_codes[] = {213, 501, 550, 0}; /* 501, 550 are incorrect codes */
+    static const int size_codes[] = {213, 0};
 
     snprintf(command, sizeof(command), "SIZE %s\r\n", s->path);
     if (ftp_send_command(s, command, size_codes, &res) == 213 && res) {
@@ -335,7 +390,7 @@ static int ftp_file_size(FTPContext *s)
 static int ftp_retrieve(FTPContext *s)
 {
     char command[CONTROL_BUFFER_SIZE];
-    static const int retr_codes[] = {150, 550, 554, 0}; /* 550, 554 are incorrect codes */
+    static const int retr_codes[] = {150, 0};
 
     snprintf(command, sizeof(command), "RETR %s\r\n", s->path);
     if (ftp_send_command(s, command, retr_codes, NULL) != 150)
@@ -363,7 +418,7 @@ static int ftp_store(FTPContext *s)
 static int ftp_type(FTPContext *s)
 {
     static const char *command = "TYPE I\r\n";
-    static const int type_codes[] = {200, 500, 504, 0}; /* 500, 504 are incorrect codes */
+    static const int type_codes[] = {200, 0};
 
     if (ftp_send_command(s, command, type_codes, NULL) != 200)
         return AVERROR(EIO);
@@ -374,7 +429,7 @@ static int ftp_type(FTPContext *s)
 static int ftp_restart(FTPContext *s, int64_t pos)
 {
     char command[CONTROL_BUFFER_SIZE];
-    static const int rest_codes[] = {350, 500, 501, 0}; /* 500, 501 are incorrect codes */
+    static const int rest_codes[] = {350, 0};
 
     snprintf(command, sizeof(command), "REST %"PRId64"\r\n", pos);
     if (ftp_send_command(s, command, rest_codes, NULL) != 350)
@@ -383,6 +438,21 @@ static int ftp_restart(FTPContext *s, int64_t pos)
     return 0;
 }
 
+static int ftp_features(FTPContext *s)
+{
+    static const char *feat_command        = "FEAT\r\n";
+    static const char *enable_utf8_command = "OPTS UTF8 ON\r\n";
+    static const int feat_codes[] = {211, 0};
+    static const int opts_codes[] = {200, 451};
+    char *feat;
+
+    if (ftp_send_command(s, feat_command, feat_codes, &feat) == 211) {
+        if (av_stristr(feat, "UTF8"))
+            ftp_send_command(s, enable_utf8_command, opts_codes, NULL);
+    }
+    return 0;
+}
+
 static int ftp_connect_control_connection(URLContext *h)
 {
     char buf[CONTROL_BUFFER_SIZE], opts_format[20], *response = NULL;
@@ -426,6 +496,8 @@ static int ftp_connect_control_connection(URLContext *h)
             av_log(h, AV_LOG_ERROR, "Set content type failed\n");
             return err;
         }
+
+        ftp_features(s);
     }
     return 0;
 }
@@ -439,8 +511,11 @@ static int ftp_connect_data_connection(URLContext *h)
 
     if (!s->conn_data) {
         /* Enter passive mode */
-        if ((err = ftp_passive_mode(s)) < 0)
-            return err;
+        if (ftp_passive_mode_epsv(s) < 0) {
+            /* Use PASV as fallback */
+            if ((err = ftp_passive_mode(s)) < 0)
+                return err;
+        }
         /* Open data connection */
         ff_url_join(buf, sizeof(buf), "tcp", NULL, s->hostname, s->server_data_port, NULL);
         if (s->rw_timeout != -1) {