Send image from flask server(python) to android app(java) [duplicate] - java

So this is embarrassing. I've got an application that I threw together in Flask and for now it is just serving up a single static HTML page with some links to CSS and JS. And I can't find where in the documentation Flask describes returning static files. Yes, I could use render_template but I know the data is not templatized. I'd have thought send_file or url_for was the right thing, but I could not get those to work. In the meantime, I am opening the files, reading content, and rigging up a Response with appropriate mimetype:
import os.path
from flask import Flask, Response
app = Flask(__name__)
app.config.from_object(__name__)
def root_dir(): # pragma: no cover
return os.path.abspath(os.path.dirname(__file__))
def get_file(filename): # pragma: no cover
try:
src = os.path.join(root_dir(), filename)
# Figure out how flask returns static files
# Tried:
# - render_template
# - send_file
# This should not be so non-obvious
return open(src).read()
except IOError as exc:
return str(exc)
#app.route('/', methods=['GET'])
def metrics(): # pragma: no cover
content = get_file('jenkins_analytics.html')
return Response(content, mimetype="text/html")
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def get_resource(path): # pragma: no cover
mimetypes = {
".css": "text/css",
".html": "text/html",
".js": "application/javascript",
}
complete_path = os.path.join(root_dir(), path)
ext = os.path.splitext(path)[1]
mimetype = mimetypes.get(ext, "text/html")
content = get_file(complete_path)
return Response(content, mimetype=mimetype)
if __name__ == '__main__': # pragma: no cover
app.run(port=80)
Someone want to give a code sample or url for this? I know this is going to be dead simple.

In production, configure the HTTP server (Nginx, Apache, etc.) in front of your application to serve requests to /static from the static folder. A dedicated web server is very good at serving static files efficiently, although you probably won't notice a difference compared to Flask at low volumes.
Flask automatically creates a /static/<path:filename> route that will serve any filename under the static folder next to the Python module that defines your Flask app. Use url_for to link to static files: url_for('static', filename='js/analytics.js')
You can also use send_from_directory to serve files from a directory in your own route. This takes a base directory and a path, and ensures that the path is contained in the directory, which makes it safe to accept user-provided paths. This can be useful in cases where you want to check something before serving the file, such as if the logged in user has permission.
from flask import send_from_directory
#app.route('/reports/<path:path>')
def send_report(path):
return send_from_directory('reports', path)
Do not use send_file or send_static_file with a user-supplied path. This will expose you to directory traversal attacks. send_from_directory was designed to safely handle user-supplied paths under a known directory, and will raise an error if the path attempts to escape the directory.
If you are generating a file in memory without writing it to the filesystem, you can pass a BytesIO object to send_file to serve it like a file. You'll need to pass other arguments to send_file in this case since it can't infer things like the file name or content type.

If you just want to move the location of your static files, then the simplest method is to declare the paths in the constructor. In the example below, I have moved my templates and static files into a sub-folder called web.
app = Flask(__name__,
static_url_path='',
static_folder='web/static',
template_folder='web/templates')
static_url_path='' removes any preceding path from the URL (i.e.
the default /static).
static_folder='web/static' to serve any files found in the folder
web/static as static files.
template_folder='web/templates' similarly, this changes the
templates folder.
Using this method, the following URL will return a CSS file:
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
And finally, here's a snap of the folder structure, where flask_server.py is the Flask instance:

You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.
app = Flask(__name__, static_url_path='/static')
With that set you can use the standard HTML:
<link rel="stylesheet" type="text/css" href="/static/style.css">

I'm sure you'll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files
Basically you just need a "static" folder at the root of your package, and then you can use url_for('static', filename='foo.bar') or directly link to your files with http://example.com/static/foo.bar.
EDIT: As suggested in the comments you could directly use the '/static/foo.bar' URL path BUT url_for() overhead (performance wise) is quite low, and using it means that you'll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).

You can use this function :
send_static_file(filename)
Function used internally to send static
files from the static folder to the browser.
app = Flask(__name__)
#app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)

What I use (and it's been working great) is a "templates" directory and a "static" directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask's templating syntax. Below is a sample call in my views.py file.
#app.route('/projects')
def projects():
return render_template("projects.html", title = 'Projects')
Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You'll probably end up doing this anyways in your CSS/JS file links in html. For instance...
<script src="{{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>
Here's a link to the "canonical" informal Flask tutorial - lots of great tips in here to help you hit the ground running.
http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

A simplest working example based on the other answers is the following:
from flask import Flask, request
app = Flask(__name__, static_url_path='')
#app.route('/index/')
def root():
return app.send_static_file('index.html')
if __name__ == '__main__':
app.run(debug=True)
With the HTML called index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<div>
<p>
This is a test.
</p>
</div>
</body>
</html>
IMPORTANT: And index.html is in a folder called static, meaning <projectpath> has the .py file, and <projectpath>\static has the html file.
If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')
EDIT: For showing all files in the folder if requested, use this
#app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
Which is essentially BlackMamba's answer, so give them an upvote.

For angular+boilerplate flow which creates next folders tree:
backend/
|
|------ui/
| |------------------build/ <--'static' folder, constructed by Grunt
| |--<proj |----vendors/ <-- angular.js and others here
| |-- folders> |----src/ <-- your js
| |----index.html <-- your SPA entrypoint
|------<proj
|------ folders>
|
|------view.py <-- Flask app here
I use following solution:
...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")
#app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
return send_from_directory(root, path)
#app.route('/', methods=['GET'])
def redirect_to_index():
return send_from_directory(root, 'index.html')
...
It helps to redefine 'static' folder to custom.

app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location

So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)

By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">

Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.

One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html

The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)

Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.

All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```

The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}

The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />

By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.

If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something

In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images

This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])

In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.

For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')

Related

"Absolute paths not recommended in JSPs" ? - Is this also apply to the #RequestMapping()?

I got warnings from IntelliJ that "Absolute paths not recommended in JSPs"
I understand that, for internal files locations, like "styles.css or script.js", we should use relative path, something like this -
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/resources/css/styles.css">
But how about the #RequestMapping(), #GetMapping, #PostMapping, ... , and etc
For example, I have a form here:
<form method="post" action="/file/upload-submitted" enctype="multipart/form-data">
...
</form>
and I also have:
#PostMapping(value = "/file/upload-submitted")
IntelliJ also give me warning "Absolute paths not recommended in JSPs" at "/file/upload"
Is it the correct warning?
***The reason that I put the absolute path there because there are multiple paths to get to the form.
#GetMapping(value = {"/file", "/file/upload"})

Thymeleaf java template engine is changing some special characters

final Context ctx = new Context();
context.setVariable("data", data);
templateEngine.process(template, context).trim();
here are the imports:
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
template variable points to "content_completed". Where this content_completed is a html file that exists in the project classpath.
contents of this html file:
<html xmlns:th="http://www.thymeleaf.org" th:inline="text" th:remove="tag">
[[${data.fileName}]][[${T(abc.composer.NoteData).COMPLETED_NO_ERRORS}]]
</html>
where NoteData is a java class
If this data.fileName has something like "sample&.text", the Thymeleaf template engine is changing it to "sample&.text".
Any thoughts on how to avoid this?
Solved it myself. Here is the solution:
<html xmlns:th="http://www.thymeleaf.org" th:inline="text" th:remove="tag">
<th:block th:utext="${data.fileName}"/>[[${T(abc.composer.NoteData).COMPLETED_NO_ERRORS}]]
</html>
Thymeleaf is escaping the filename so that a browser does not interpret the & as a special HTML character (it's used for HTML entities).
So, the answer, I think, is that it's doing the right thing. When you view the HTML output in a browser it will render as you are expecting.

Spring dynamic url access to css/js files

I have a simple Spring boot application. There URL that would be used here is going to be like:
sub.domain.com/variable1/variable2
and variable1 and variable2 can be anything for example:
sub.domain.com/kfc/foo
sub.domain.com/subway/boo
and I capture those in my controller as below:
#Controller
public class IndexController {
#RequestMapping(value="/{var1}/{var2}", method = RequestMethod.GET)
public String Index(#PathVariable(value="var1") String variable1, #PathVariable(value="var2") String variable2) {
return "/index.html";
}
}
which will redirect to my html page which is located at src/main/webapp/index.html
so the index page is loaded under the dynamic url but then none of the scrips or stylesheets are found because it's trying to find them under variable1 path.
for example if I have
sub.domain.com/kfc/foo
and my link to css in the index.html is
<link rel="stylesheet" href="styles/index.css" />
it will try to find the index.css under
sub.domain.com/kfc/styles/index.css
how can I tell the app to look into the right place for the styles or js files?
index.html is trying to load styles from a relative path.
In order for index.html to load styles under sub.domain.com/styles/index.css, add a / in link tag **/**styles/index.css <link rel="stylesheet" href="/styles/index.css" />

NoClassDefFound error, java

My class's code:
package overviewPack;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ButtonScreen extends JApplet implements ActionListener{
JButton middle = new JButton();
Container screen = getContentPane();
public void init(){
setVisible(true);
middle.addActionListener(this);
screen.add(middle);
}
public void actionPerformed(ActionEvent event) {
if (event.getSource() == middle){
System.out.println("hey");
}
}
}
When I attempt to run it using html, I recieve a noclassdefFound error, with the stacktrace as ButtonScreen(Wrong name: overviewPack ButtonScreen)
Here is my html code: (I use brackets so that the code will turn up in chat as the code and not the finished product).
<HEAD>
<TITLE>
A Simple Program </TITLE>
</HEAD>
<BODY>
Here is the output of my program:
<APPLET CODE="overviewPack.ButtonScreen.class" codebase = "bin" WIDTH=150 HEIGHT=25>
</APPLET>
</BODY>
</HTML>
I have tried many different formats for the html, and looked at many other people's similar, sometimes exactly the same errors, but none of the solutions proposed to other people have worked. I have also looked around on the rest of the net for a solution, but I have found none.
This error happens with all my applets, even this extremely simple applet I did above.
The html file is in the same folder as the class
The HTML file is in the same folder as the class
That is no good. You need to understand how the parameters in the applet element work.
<APPLET CODE="overviewPack.ButtonScreen.class" codebase="bin" WIDTH=150 HEIGHT=25>
Let us say that the HTML is located at: our.com/applets/applet1.html.
codebase = "bin" would mean the classpath starts with our.com/applets/bin/.
overviewPack.ButtonScreen.class would therefore need to be found at:
our.com/applets/bin/overviewPack/ButtonScreen.class
Note that the package overviewPack has become an inherent part of the correct path to the class file. That is where the 'wrong name' is originating from. The JRE seems to be searching the directory of the HTML, locating the class in the same directory, then loading it to discover it is in the wrong path.
Code Attribute
<APPLET CODE="overviewPack.ButtonScreen.class" codebase="bin" WIDTH=150 HEIGHT=25>
Note the required value is the Fully Qualified Name of the class file. That consists of the package(s) name, followed by the class name, each separated by a dot. E.G.
overviewPack.ButtonScreen
As opposed to
overviewPack.ButtonScreen.class // combination of FQN with file type
or
overviewPack/ButtonScreen.class // relative file path on server
So the opening APPLET element should best be:
<APPLET CODE="overviewPack.ButtonScreen" codebase="bin" WIDTH=150 HEIGHT=25>
Sometimes there is a problem with the .class file extension at the end of the code= attribute. Some doc I've seen says that the code= attribute has the classname in which case having the .class at the end is wrong. The classname is: overviewPack.ButtonScreen and the filename is:
ButtonScreen.class

Searching for a valid pattern in files of under a folder? (Maybe with Perl or with some Apis at Java or anything else)

I have a folder and it's name is v3. There are jsp files in that folder also in v3 folder there are some folders and there are jsp files in that folder too.
My jsp folders have some links as like:
<link rel="stylesheet" href="/static/css/main.css" type="text/css" />
<link rel="stylesheet" type="text/css" href="/css<s:text name="scripts"/>/general_styles.css">
<link rel="stylesheet" type="text/css" href="/v3/css<s:text name="scripts"/>/something.css" >
and scripts:
<script language="javascript" type="text/javascript" src="/static/scripts/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/scripts<s:text name="scripts"/>/prototype-1.6.0.2.js"></script>
<script language="javascript" type="text/javascript" src="/scripts<s:text name="scripts"/>/${a.name}/<s:text name="genericJs"/>"></script>
For links:
href should start with /static/ for example this is valid:
<link rel="stylesheet" href="/static/css/main.css" type="text/css" />
For scripts:
src should start with /static/ too for example this is valid:
<script language="javascript" type="text/javascript" src="/static/scripts/jquery-1.4.2.min.js"></script>
What I want to do that I want to detect which files has not valid definitions.
EDIT: Valid - not valid is a notion for my company's system. We are moving our css and js folders to another and they will be under a folder and that folder's name is v3.
The program will work like that:
jsp files are under v3 folder. I will run that program from anywhere and it will check all the jsp files under that folder(I will define the whole path of that v3 folder in the written program).
It will find all lines that start with <link and <script.
If it is <link it will find href="
If it is <script it will find src="
After it finds one of them it will check that does it start with /static/ or not.
If starts it is OK but if doesn't it will write the file name to output/text file or anything else.
You might look into ack, it is a Perl-based replacement for grep and should be able to do what you want.
Truthfully you don't want to do pattern matching on [xht]ml, you want to use a parser. A Perl script using HTML::TokeParser can find all tags with certain attributes.
Here is a quick mock-up, though you may want some more useful output:
#!/usr/bin/perl
use strict;
use warnings;
use File::chdir;
use Cwd 'abs_path';
use HTML::TokeParser;
my #paths = #ARGV;
my #files;
foreach my $path (#paths) {
local $CWD = $path;
opendir( my $dh, $CWD);
push #files, map { abs_path($_) } grep {/\.jsp$/} readdir $dh;
}
foreach my $file (#files) {
my $parser = HTML::TokeParser->new($file);
while (my $tag = $parser->get_tag("link", "script")) {
if ($tag->[0] eq "link" and exists $tag->[1]{'href'}) {
print "$file\n" unless $tag->[1]{'href'} =~ m#^/static/#;
} elsif ($tag->[0] eq "script" and exists $tag->[1]{'src'}) {
print "$file\n" unless $tag->[1]{'src'} =~ m#^/static/#;
}
}
}
Use HTML::TreeBuilder (and thus HTML::Element) and look_down to find your stuff.
use strict;
use warnings;
use 5.012;
use HTML::TreeBuilder;
my #filelist = #ARGV; ### or some other method ofc.
for my $file (#filelist) {
my $tree = HTML::TreeBuilder->new_from_file($file)->elementify;
for my $e ( $tree->look_down( '_tag' => 'link',
sub { !($_[0]->attr('href') =~ |^/static/|) }
)
) {
say "$file: ", $e->as_HTML;
}
}
It's also then pretty trivial to modify your HTML with the same script (ie, concatenate '/static/' to the front of the bad attributes -- $e->attr('href') = '/static/' . $e->attr('href')) and spit it back out with HTML::Tidy with HTML::Tidy->new->clean($tree->as_HTML).
Edit: Re your question about the file list, assigning ARGV to the file list was done simply because it was tangential to the question. See How do I search a directory for all .XXX files and get a list of them in Perl? for example. I'd use File::Find:
use File::Find;
my #rootdirs = #ARGV or die "Please pass all root directories to search as arguments!";
my #filelist = find( sub { /\.jsp$/ or return; }, #rootdirs );
That would recurse through your starting directories (passed by argument -- you could also assign them directly to #rootdirs if you prefer) and give you all the .jsp files in them as items in #filelist.
Well, something like this will get you going:
public static void main(String[] args) throws IOException {
Iterator<File> files = FileUtils.iterateFiles(new File("/path/to/v3"), new String[]{"jsp"}, true);
while (files.hasNext()) {
File jsp = files.next();
List<String> list = FileUtils.readLines(jsp);
for (String line : list) {
if(line.startsWith("<link") || line.startsWith("<script")) {
if(!line.contains("/static")) {
throw new RuntimeException("invalid file found: " + jsp.getAbsolutePath());
}
}
}
}
}
Edited to contain changes discussed in comments

Categories