Repository: mlflow/mlflow

Issue:
[BUG] MLFlow served model fails to handle request with http url inside.
Thank you for submitting an issue. Please refer to our [issue policy](https://www.github.com/mlflow/mlflow/blob/master/ISSUE_POLICY.md) for additional information about bug reports. For help with debugging your code, please refer to [Stack Overflow](https://stackoverflow.com/questions/tagged/mlflow).

**Please fill in this bug report template to ensure a timely and thorough response.**

### Willingness to contribute
The MLflow Community encourages bug fix contributions. Would you or another member of your organization be willing to contribute a fix for this bug to the MLflow code base?

- [ ] Yes. I can contribute a fix for this bug independently.
- [ ] Yes. I would be willing to contribute a fix for this bug with guidance from the MLflow community.
- [x] No. I cannot contribute a bug fix at this time.

### System information
pandas==1.1.4

### Describe the problem
Describe the problem clearly here. Include descriptions of the expected behavior and the actual behavior.
When a request with `http://url` in data, pandas will try to load data from the given url.

### Code to reproduce issue
Provide a reproducible test case that is the bare minimum necessary to generate the problem.
```bash
curl -x POST -H 'ContentType: application/json' -d "{\"data\":[[\"http://google.com\"]],\"columns\":[\"f\",]}" $A_MLFLOW_SERVED_MODEL
```

### Other info / logs
Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached.
```bash
  File "/miniconda3/envs/test/lib/python3.7/site-packages/pandas/util/_decorators.py", line 199, in wrapper
    return func(*args, **kwargs)
  File "/miniconda3/envs/test/lib/python3.7/site-packages/pandas/util/_decorators.py", line 296, in wrapper
    return func(*args, **kwargs)
  File "/miniconda3/envs/test/lib/python3.7/site-packages/pandas/io/json/_json.py", line 594, in read_json
    path_or_buf, encoding=encoding, compression=compression
  File "/miniconda3/envs/test/lib/python3.7/site-packages/pandas/io/common.py", line 203, in get_filepath_or_buffer
    fsspec = import_optional_dependency("fsspec")
  File "/miniconda3/envs/test/lib/python3.7/site-packages/pandas/compat/_optional.py", line 110, in import_optional_dependency
    raise ImportError(msg) from None
ImportError: Missing optional dependency 'fsspec'.  Use pip or conda to install fsspec.
```

### What component(s), interfaces, languages, and integrations does this bug affect?
Components 
- [ ] `area/artifacts`: Artifact stores and artifact logging
- [ ] `area/build`: Build and test infrastructure for MLflow
- [ ] `area/docs`: MLflow documentation pages
- [ ] `area/examples`: Example code
- [ ] `area/model-registry`: Model Registry service, APIs, and the fluent client calls for Model Registry
- [ ] `area/models`: MLmodel format, model serialization/deserialization, flavors
- [ ] `area/projects`: MLproject format, project running backends
- [x] `area/scoring`: Local serving, model deployment tools, spark UDFs
- [ ] `area/server-infra`: MLflow server, JavaScript dev server
- [ ] `area/tracking`: Tracking Service, tracking client APIs, autologging

Interface 
- [ ] `area/uiux`: Front-end, user experience, JavaScript, plotting
- [ ] `area/docker`: Docker use across MLflow's components, such as MLflow Projects and MLflow Models
- [ ] `area/sqlalchemy`: Use of SQLAlchemy in the Tracking Service or Model Registry
- [ ] `area/windows`: Windows support

Language 
- [ ] `language/r`: R APIs and clients
- [ ] `language/java`: Java APIs and clients
- [ ] `language/new`: Proposals for new client languages

Integrations
- [ ] `integrations/azure`: Azure and Azure ML integrations
- [ ] `integrations/sagemaker`: SageMaker integrations
- [ ] `integrations/databricks`: Databricks integrations



Discussion:

Resolving patch:
diff --git a/mlflow/pyfunc/scoring_server/__init__.py b/mlflow/pyfunc/scoring_server/__init__.py
--- a/mlflow/pyfunc/scoring_server/__init__.py
+++ b/mlflow/pyfunc/scoring_server/__init__.py
@@ -288,11 +288,15 @@ def transformation():  # pylint: disable=unused-variable
             data = infer_and_parse_json_input(json_str, input_schema)
         elif flask.request.content_type == CONTENT_TYPE_JSON_SPLIT_ORIENTED:
             data = parse_json_input(
-                json_input=flask.request.data.decode("utf-8"), orient="split", schema=input_schema
+                json_input=StringIO(flask.request.data.decode("utf-8")),
+                orient="split",
+                schema=input_schema,
             )
         elif flask.request.content_type == CONTENT_TYPE_JSON_RECORDS_ORIENTED:
             data = parse_json_input(
-                json_input=flask.request.data.decode("utf-8"), orient="records", schema=input_schema
+                json_input=StringIO(flask.request.data.decode("utf-8")),
+                orient="records",
+                schema=input_schema,
             )
         elif flask.request.content_type == CONTENT_TYPE_JSON_SPLIT_NUMPY:
             data = parse_split_oriented_json_input_to_numpy(flask.request.data.decode("utf-8"))


Test patch:
diff --git a/tests/pyfunc/test_scoring_server.py b/tests/pyfunc/test_scoring_server.py
--- a/tests/pyfunc/test_scoring_server.py
+++ b/tests/pyfunc/test_scoring_server.py
@@ -619,3 +619,27 @@ def test_get_jsonnable_obj():
     assert json.dumps(py_ary, cls=NumpyEncoder) == json.dumps(np_ary, cls=NumpyEncoder)
     np_ary = _get_jsonable_obj(np.array(py_ary, dtype=type(str)))
     assert json.dumps(py_ary, cls=NumpyEncoder) == json.dumps(np_ary, cls=NumpyEncoder)
+
+
+@pytest.mark.large
+def test_parse_json_input_including_path():
+    class TestModel(PythonModel):
+        def predict(self, context, model_input):
+            return 1
+
+    with mlflow.start_run() as run:
+        mlflow.pyfunc.log_model("model", python_model=TestModel())
+
+    pandas_split_content = pd.DataFrame(
+        {
+            "url": ["http://foo.com", "https://bar.com"],
+            "bad_protocol": ["aaa://bbb", "address:/path"],
+        }
+    ).to_json(orient="split")
+
+    response_records_content_type = pyfunc_serve_and_score_model(
+        model_uri="runs:/{}/model".format(run.info.run_id),
+        data=pandas_split_content,
+        content_type=pyfunc_scoring_server.CONTENT_TYPE_JSON,
+    )
+    assert response_records_content_type.status_code == 200