Created
February 21, 2014 23:31
-
-
Save fredemmott/9145911 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 7ef637d6c0fd5d0736dab8a7b7fd2e4eb3730207 | |
Author: Fred Emmott <fredemmott@fb.com> | |
Date: Fri Feb 21 14:31:31 2014 -0800 | |
Add plumbing for stream metadata; implement for php:// | |
Summary: Match Zend. refs guzzle/guzzle#538 | |
Test Plan: New test | |
Reviewers: ptarjan | |
CC: smith, ps, hphp-diffs@lists | |
Differential Revision: https://phabricator.fb.com/D1185448 | |
Task ID: 3712919 | |
diff --git a/hphp/runtime/base/file.cpp b/hphp/runtime/base/file.cpp | |
index e8889dd..f35f074 100644 | |
--- a/hphp/runtime/base/file.cpp | |
+++ b/hphp/runtime/base/file.cpp | |
@@ -152,10 +152,10 @@ Variant File::Open(const String& filename, const String& mode, | |
/////////////////////////////////////////////////////////////////////////////// | |
// constructor and destructor | |
-File::File(bool nonblocking) | |
+File::File(bool nonblocking, const String& wrapper, const String& stream_type) | |
: m_isLocal(false), m_fd(-1), m_closed(false), m_nonblocking(nonblocking), | |
m_writepos(0), m_readpos(0), m_position(0), m_eof(false), | |
- m_buffer(nullptr) { | |
+ m_wrapperType(wrapper), m_streamType(stream_type), m_buffer(nullptr) { | |
} | |
File::~File() { | |
@@ -391,7 +391,7 @@ const StaticString | |
Array File::getMetaData() { | |
ArrayInit ret(10); | |
- ret.set(s_wrapper_type, o_getClassName()); | |
+ ret.set(s_wrapper_type, getWrapperType()); | |
ret.set(s_stream_type, getStreamType()); | |
ret.set(s_mode, String(m_mode)); | |
ret.set(s_unread_bytes, 0); | |
@@ -404,6 +404,13 @@ Array File::getMetaData() { | |
return ret.create(); | |
} | |
+String File::getWrapperType() const { | |
+ if (m_wrapperType.empty()) { | |
+ return o_getClassName(); | |
+ } | |
+ return m_wrapperType; | |
+} | |
+ | |
/////////////////////////////////////////////////////////////////////////////// | |
// utility functions | |
diff --git a/hphp/runtime/base/file.h b/hphp/runtime/base/file.h | |
index 118ded9..b86e4d3 100644 | |
--- a/hphp/runtime/base/file.h | |
+++ b/hphp/runtime/base/file.h | |
@@ -66,7 +66,9 @@ public: | |
public: | |
static const int USE_INCLUDE_PATH; | |
- explicit File(bool nonblocking = true); | |
+ explicit File(bool nonblocking = true, | |
+ const String& wrapper_type = null_string, | |
+ const String& stream_type = empty_string); | |
virtual ~File(); | |
static StaticString& classnameof() { | |
@@ -126,7 +128,8 @@ public: | |
virtual Array getMetaData(); | |
virtual Array getWrapperMetaData() { return null_array; } | |
- virtual const char *getStreamType() const { return "";} | |
+ String getWrapperType() const; | |
+ String getStreamType() const { return m_streamType; } | |
Resource &getStreamContext() { return m_streamContext; } | |
void setStreamContext(Resource &context) { m_streamContext = context; } | |
@@ -191,6 +194,8 @@ protected: | |
std::string m_name; | |
std::string m_mode; | |
+ String m_wrapperType; | |
+ String m_streamType; | |
Resource m_streamContext; | |
void closeImpl(); | |
diff --git a/hphp/runtime/base/mem-file.cpp b/hphp/runtime/base/mem-file.cpp | |
index 98b142d..211bc7c 100644 | |
--- a/hphp/runtime/base/mem-file.cpp | |
+++ b/hphp/runtime/base/mem-file.cpp | |
@@ -26,13 +26,16 @@ namespace HPHP { | |
/////////////////////////////////////////////////////////////////////////////// | |
-MemFile::MemFile() | |
- : File(false), m_data(nullptr), m_len(-1), m_cursor(0), m_malloced(false) { | |
+MemFile::MemFile(const String& wrapper, const String& stream) | |
+ : File(false, wrapper, stream), m_data(nullptr), m_len(-1), m_cursor(0), | |
+ m_malloced(false) { | |
m_isLocal = true; | |
} | |
-MemFile::MemFile(const char *data, int64_t len) | |
- : File(false), m_data(nullptr), m_len(len), m_cursor(0), m_malloced(true) { | |
+MemFile::MemFile(const char *data, int64_t len, | |
+ const String& wrapper, const String& stream) | |
+ : File(false, wrapper, stream), m_data(nullptr), m_len(len), m_cursor(0), | |
+ m_malloced(true) { | |
m_data = (char*)malloc(len + 1); | |
if (m_data && len) { | |
memcpy(m_data, data, len); | |
diff --git a/hphp/runtime/base/mem-file.h b/hphp/runtime/base/mem-file.h | |
index 21244b7..d32461d 100644 | |
--- a/hphp/runtime/base/mem-file.h | |
+++ b/hphp/runtime/base/mem-file.h | |
@@ -30,8 +30,11 @@ class MemFile : public File { | |
public: | |
DECLARE_RESOURCE_ALLOCATION(MemFile); | |
- MemFile(); | |
- MemFile(const char *data, int64_t len); | |
+ explicit MemFile(const String& wrapper_type = null_string, | |
+ const String& stream_type = empty_string); | |
+ MemFile(const char *data, int64_t len, | |
+ const String& wrapper_type = null_string, | |
+ const String& stream_type = empty_string); | |
virtual ~MemFile(); | |
CLASSNAME_IS("MemFile"); | |
diff --git a/hphp/runtime/base/output-file.cpp b/hphp/runtime/base/output-file.cpp | |
index 05bf0ce..90ba86b 100644 | |
--- a/hphp/runtime/base/output-file.cpp | |
+++ b/hphp/runtime/base/output-file.cpp | |
@@ -25,8 +25,10 @@ namespace HPHP { | |
// constructor and destructor | |
const StaticString s_php_output("php://output"); | |
+const StaticString s_php("PHP"); | |
+const StaticString s_output("Output"); | |
-OutputFile::OutputFile(const String& filename) { | |
+OutputFile::OutputFile(const String& filename): File(true, s_php, s_output) { | |
if (filename != s_php_output) { | |
throw FatalErrorException("not a php://output file "); | |
} | |
diff --git a/hphp/runtime/base/php-stream-wrapper.cpp b/hphp/runtime/base/php-stream-wrapper.cpp | |
index 69e4f48..89fad48 100644 | |
--- a/hphp/runtime/base/php-stream-wrapper.cpp | |
+++ b/hphp/runtime/base/php-stream-wrapper.cpp | |
@@ -26,6 +26,11 @@ | |
namespace HPHP { | |
/////////////////////////////////////////////////////////////////////////////// | |
+const StaticString s_php("PHP"); | |
+const StaticString s_input("Input"); | |
+const StaticString s_temp("TEMP"); | |
+const StaticString s_memory("MEMORY"); | |
+ | |
File *PhpStreamWrapper::openFD(const char *sFD) { | |
if (!RuntimeOption::ClientExecutionMode()) { | |
raise_warning("Direct access to file descriptors " | |
@@ -47,7 +52,7 @@ File *PhpStreamWrapper::openFD(const char *sFD) { | |
return nullptr; | |
} | |
- return NEWOBJ(PlainFile)(dup(nFD), true); | |
+ return NEWOBJ(PlainFile)(dup(nFD), true, s_php); | |
} | |
@@ -60,21 +65,28 @@ File* PhpStreamWrapper::open(const String& filename, const String& mode, | |
const char *req = filename.c_str() + sizeof("php://") - 1; | |
if (!strcasecmp(req, "stdin")) { | |
- return NEWOBJ(PlainFile)(dup(STDIN_FILENO), true); | |
+ return NEWOBJ(PlainFile)(dup(STDIN_FILENO), true, s_php); | |
} | |
if (!strcasecmp(req, "stdout")) { | |
- return NEWOBJ(PlainFile)(dup(STDOUT_FILENO), true); | |
+ return NEWOBJ(PlainFile)(dup(STDOUT_FILENO), true, s_php); | |
} | |
if (!strcasecmp(req, "stderr")) { | |
- return NEWOBJ(PlainFile)(dup(STDERR_FILENO), true); | |
+ return NEWOBJ(PlainFile)(dup(STDERR_FILENO), true, s_php); | |
} | |
if (!strncasecmp(req, "fd/", sizeof("fd/") - 1)) { | |
return openFD(req + sizeof("fd/") - 1); | |
} | |
- if (!strncasecmp(req, "temp", sizeof("temp") - 1) || | |
- !strcasecmp(req, "memory")) { | |
- std::unique_ptr<TempFile> file(NEWOBJ(TempFile)()); | |
+ if (!strncasecmp(req, "temp", sizeof("temp") - 1)) { | |
+ std::unique_ptr<TempFile> file(NEWOBJ(TempFile)(true, s_php, s_temp)); | |
+ if (!file->valid()) { | |
+ raise_warning("Unable to create temporary file"); | |
+ return nullptr; | |
+ } | |
+ return file.release(); | |
+ } | |
+ if (!strcasecmp(req, "memory")) { | |
+ std::unique_ptr<TempFile> file(NEWOBJ(TempFile)(true, s_php, s_memory)); | |
if (!file->valid()) { | |
raise_warning("Unable to create temporary file"); | |
return nullptr; | |
@@ -84,7 +96,7 @@ File* PhpStreamWrapper::open(const String& filename, const String& mode, | |
if (!strcasecmp(req, "input")) { | |
auto raw_post = g_context->getRawPostData(); | |
- return NEWOBJ(MemFile)(raw_post.c_str(), raw_post.size()); | |
+ return NEWOBJ(MemFile)(raw_post.c_str(), raw_post.size(), s_php, s_input); | |
} | |
if (!strcasecmp(req, "output")) { | |
diff --git a/hphp/runtime/base/plain-file.cpp b/hphp/runtime/base/plain-file.cpp | |
index 5e118cb..942a639 100644 | |
--- a/hphp/runtime/base/plain-file.cpp | |
+++ b/hphp/runtime/base/plain-file.cpp | |
@@ -25,11 +25,18 @@ | |
namespace HPHP { | |
+const StaticString s_plainfile("plainfile"); | |
+const StaticString s_stdio("STDIO"); | |
+ | |
/////////////////////////////////////////////////////////////////////////////// | |
// constructor and destructor | |
-PlainFile::PlainFile(FILE *stream, bool nonblocking) | |
- : File(nonblocking), m_stream(stream), m_buffer(nullptr) { | |
+PlainFile::PlainFile(FILE *stream, bool nonblocking, | |
+ const String& wrapper_type, const String& stream_type) | |
+ : File(nonblocking, | |
+ wrapper_type.isNull() ? s_plainfile : wrapper_type, | |
+ stream_type.isNull() ? s_stdio : stream_type), | |
+ m_stream(stream), m_buffer(nullptr) { | |
if (stream) { | |
m_fd = fileno(stream); | |
m_buffer = (char *)malloc(BUFSIZ); | |
@@ -39,8 +46,12 @@ PlainFile::PlainFile(FILE *stream, bool nonblocking) | |
m_isLocal = true; | |
} | |
-PlainFile::PlainFile(int fd, bool nonblocking) | |
- : File(nonblocking), m_stream(nullptr), m_buffer(nullptr) { | |
+PlainFile::PlainFile(int fd, bool nonblocking, | |
+ const String& wrapper_type, const String& stream_type) | |
+ : File(nonblocking, | |
+ wrapper_type.isNull() ? s_plainfile : wrapper_type, | |
+ stream_type.isNull() ? s_stdio : stream_type), | |
+ m_stream(nullptr), m_buffer(nullptr) { | |
m_fd = fd; | |
} | |
diff --git a/hphp/runtime/base/plain-file.h b/hphp/runtime/base/plain-file.h | |
index 92acf5f..ac312905 100644 | |
--- a/hphp/runtime/base/plain-file.h | |
+++ b/hphp/runtime/base/plain-file.h | |
@@ -30,8 +30,14 @@ class PlainFile : public File { | |
public: | |
DECLARE_RESOURCE_ALLOCATION(PlainFile); | |
- explicit PlainFile(FILE *stream = nullptr, bool nonblocking = false); | |
- explicit PlainFile(int fd, bool nonblocking = false); | |
+ explicit PlainFile(FILE *stream = nullptr, | |
+ bool nonblocking = false, | |
+ const String& wrapper_type = null_string, | |
+ const String& stream_type = null_string); | |
+ explicit PlainFile(int fd, | |
+ bool nonblocking = false, | |
+ const String& wrapper = null_string, | |
+ const String& stream_type = null_string); | |
virtual ~PlainFile(); | |
// overriding ResourceData | |
@@ -55,7 +61,6 @@ public: | |
virtual bool stat(struct stat *sb); | |
FILE *getStream() { return m_stream;} | |
- virtual const char *getStreamType() const { return "STDIO";} | |
protected: | |
FILE *m_stream; | |
diff --git a/hphp/runtime/base/temp-file.cpp b/hphp/runtime/base/temp-file.cpp | |
index d0f6d10..a5aa47e 100644 | |
--- a/hphp/runtime/base/temp-file.cpp | |
+++ b/hphp/runtime/base/temp-file.cpp | |
@@ -23,7 +23,11 @@ namespace HPHP { | |
/////////////////////////////////////////////////////////////////////////////// | |
// constructor and destructor | |
-TempFile::TempFile(bool autoDelete /* = true */) : m_autoDelete(autoDelete) { | |
+TempFile::TempFile(bool autoDelete /* = true */, | |
+ const String& wrapper_type, | |
+ const String& stream_type) | |
+ : PlainFile(nullptr, false, wrapper_type, stream_type), | |
+ m_autoDelete(autoDelete) { | |
char path[PATH_MAX]; | |
// open a temporary file | |
diff --git a/hphp/runtime/base/temp-file.h b/hphp/runtime/base/temp-file.h | |
index 7e0d0ad..ca19464 100644 | |
--- a/hphp/runtime/base/temp-file.h | |
+++ b/hphp/runtime/base/temp-file.h | |
@@ -30,7 +30,9 @@ class TempFile : public PlainFile { | |
public: | |
DECLARE_RESOURCE_ALLOCATION(TempFile); | |
- explicit TempFile(bool autoDelete = true); | |
+ explicit TempFile(bool autoDelete = true, | |
+ const String& wrapper_type = null_string, | |
+ const String& stream_type = empty_string); | |
virtual ~TempFile(); | |
// overriding ResourceData | |
@@ -44,6 +46,8 @@ private: | |
bool m_autoDelete; | |
std::string m_rawName; | |
+ String m_wrapperType; | |
+ | |
bool closeImpl(); | |
}; | |
diff --git a/hphp/test/slow/streams/php-wrapper-stream-types.php b/hphp/test/slow/streams/php-wrapper-stream-types.php | |
new file mode 100644 | |
index 0000000..05314be | |
--- /dev/null | |
+++ b/hphp/test/slow/streams/php-wrapper-stream-types.php | |
@@ -0,0 +1,27 @@ | |
+<?php | |
+ | |
+function main() { | |
+ $to_open = array( | |
+ array('php://stdin', 'r'), | |
+ array('php://stdout', 'w'), | |
+ array('php://stderr', 'w'), | |
+ array('php://fd/1', 'w'), // stdout | |
+ array('php://temp', 'rw+'), | |
+ array('php://memory', 'rw+'), | |
+ array('php://input', 'r'), | |
+ array('php://output', 'w'), | |
+ ); | |
+ foreach ($to_open as $target) { | |
+ $stream = call_user_func_array('fopen', $target); | |
+ $metadata = stream_get_meta_data($stream); | |
+ var_dump( | |
+ array( | |
+ 'target' => $target[0], | |
+ 'wrapper' => $metadata['wrapper_type'], | |
+ 'stream' => $metadata['stream_type'], | |
+ ) | |
+ ); | |
+ } | |
+} | |
+ | |
+main(); | |
diff --git a/hphp/test/slow/streams/php-wrapper-stream-types.php.expect b/hphp/test/slow/streams/php-wrapper-stream-types.php.expect | |
new file mode 100644 | |
index 0000000..7da2ef3 | |
--- /dev/null | |
+++ b/hphp/test/slow/streams/php-wrapper-stream-types.php.expect | |
@@ -0,0 +1,64 @@ | |
+array(3) { | |
+ ["target"]=> | |
+ string(11) "php://stdin" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(5) "STDIO" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(12) "php://stdout" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(5) "STDIO" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(12) "php://stderr" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(5) "STDIO" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(10) "php://fd/1" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(5) "STDIO" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(10) "php://temp" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(4) "TEMP" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(12) "php://memory" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(6) "MEMORY" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(11) "php://input" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(5) "Input" | |
+} | |
+array(3) { | |
+ ["target"]=> | |
+ string(12) "php://output" | |
+ ["wrapper"]=> | |
+ string(3) "PHP" | |
+ ["stream"]=> | |
+ string(6) "Output" | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment